From 44b013147e6ac6da516b6b11636b58db135e1a1c Mon Sep 17 00:00:00 2001 From: Benjamin Toby Date: Thu, 21 Sep 2023 15:00:04 +0100 Subject: [PATCH] updates --- .gitignore | 276 +++--- README.md | 236 ++--- client/auth/github/getAccessToken.js | 72 +- client/auth/google/getAccessToken.js | 226 ++--- client/auth/logout.js | 292 +++--- client/index.js | 94 +- client/media/client.js | 98 +- client/media/imageInputFileToBase64.js | 222 ++--- client/media/imageInputToBase64.js | 202 ++-- client/media/inputFileToBase64.js | 192 ++-- client/utils/parseClientCookies.js | 130 +-- console-colors.js | 62 +- engine/dsql.js | 232 ++--- engine/dump.js | 106 +- engine/engine/addUsersTableToDb.js | 154 +-- engine/engine/createDbFromSchema.js | 514 +++++----- engine/engine/data/dataTypes.json | 146 +-- engine/engine/data/defaultFields.json | 78 +- engine/engine/data/possibleFields.json | 34 +- engine/engine/data/presets/users.json | 264 ++--- .../engine/utils/camelJoinedtoCamelSpace.js | 108 +-- engine/engine/utils/createTable.js | 224 ++--- engine/engine/utils/dbHandler.js | 330 ++++--- engine/engine/utils/defaultFieldsRegexp.js | 26 +- engine/engine/utils/endConnection.js | 32 +- .../engine/utils/generateColumnDescription.js | 136 +-- engine/engine/utils/noDatabaseDbHandler.js | 178 ++-- engine/engine/utils/parseDbResults.js | 152 +-- engine/engine/utils/slugToCamelTitle.js | 32 +- engine/engine/utils/supplementTable.js | 96 +- engine/engine/utils/updateTable.js | 914 +++++++++--------- engine/engine/utils/varDatabaseDbHandler.js | 196 ++-- engine/query/get.js | 202 ++-- engine/query/post.js | 200 ++-- .../query/update-api-schema-from-local-db.js | 286 +++--- engine/query/utils/addDbEntry.js | 324 +++---- engine/query/utils/deleteDbEntry.js | 152 +-- engine/query/utils/runQuery.js | 330 +++---- engine/query/utils/updateDbEntry.js | 298 +++--- engine/user/add-user.js | 306 +++--- engine/user/get-user.js | 106 +- engine/user/login-user.js | 304 +++--- engine/user/reauth-user.js | 212 ++-- engine/user/social/github-auth.js | 268 ++--- engine/user/social/google-auth.js | 338 +++---- engine/user/social/utils/githubLogin.js | 328 +++---- engine/user/social/utils/handleSocialDb.js | 752 +++++++------- engine/user/social/utils/httpsRequest.js | 210 ++-- engine/user/update-user.js | 170 ++-- functions/decrypt.js | 92 +- functions/encrypt.js | 90 +- functions/hashPassword.js | 54 +- package.json | 2 +- types/database-schema.td.js | 190 ++-- types/engine.td.js | 178 ++-- types/general.td.js | 22 +- types/mysql.td.js | 96 +- types/user.td.js | 30 +- users/add-user.js | 268 ++--- users/get-token.js | 212 ++-- users/get-user.js | 288 +++--- users/login-user.js | 408 ++++---- users/logout-user.js | 148 +-- users/reauth-user.js | 380 ++++---- users/social/github-auth.js | 502 +++++----- users/social/google-auth.js | 478 ++++----- users/update-user.js | 252 ++--- users/user-auth.js | 286 +++--- users/validate-token.js | 192 ++-- utils/delete-file.js | 220 ++--- utils/functions/parseCookies.js | 138 +-- utils/functions/sanitizeSql.js | 368 +++---- utils/get-schema.js | 178 ++-- utils/get.js | 268 ++--- utils/post.js | 362 +++---- utils/upload-file.js | 230 ++--- utils/upload-image.js | 234 ++--- 77 files changed, 8511 insertions(+), 8495 deletions(-) diff --git a/.gitignore b/.gitignore index 7fd1932..c137df4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,139 +1,139 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -*.env -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp -.cache - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - -# typescript -tsconfig.json - -# others -deprecated -.tmp +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +*.env +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# typescript +tsconfig.json + +# others +deprecated +.tmp test/ \ No newline at end of file diff --git a/README.md b/README.md index 309973a..910279e 100644 --- a/README.md +++ b/README.md @@ -1,118 +1,118 @@ -# Datasquirel - -This package requires an account with datasquirel, so be sure to create an account at [datasquirel-create-account](https://datasquirel.com/create-account) before you continue. - -## Instalation - -```bash -$ npm install datasquirel -``` - -Once the package is installed, you can import the library using `require` approach: - -```js -const datasquirel = require("datasquirel"); -``` - -## Usage - -### Fetch Data - -This method requires a readonly key or fullaccess API key gotten from [datasquirel](https://datasquirel.com/). It uses a basic https get request paired with some query params. - -```js -const datasquirel = require("datasquirel"); - -const getData = await datasquirel.get({ - key: "aldhkf89asdflksdafh908asdfjkhasdf", // Readonly API Key - db: "my_database", // Database name slug (Eg. Db Name => My Database, Db Slug => my_database) - query: "SELECT * FROM blog_posts", // SQL Query -}); -``` - -Datasquirel uses all conventional SQL query commands. However you can only use the `SELECT` command when using a readonly API key. - -### Post Data - -This method requires a fullaccess API key gotten from [datasquirel](https://datasquirel.com/). You can perform a basic fetch with this method, as well as more complex operations like `UPDATE`, `DELETE` and `INSERT`. - -```js -const datasquirel = require("datasquirel"); - -const postData = await datasquirel.post({ - key: "aldhkf89asdflksdafh908asdfjkhasdf", // Fullaccess API Key - payload: { - action: "insert", // OR "update" OR "delete" OR "select" - data: { - user_id: "19aisdn123", - user_first_name: "John", - user_last_name: "Doe", - }, - table: "users", - }, -}); -``` - -You can simply replace the `payload` object with an SQL string and it does everything you provide in the SQL command. - -```js -const datasquirel = require("datasquirel"); - -const postData = await datasquirel.post({ - key: process.env.FULL_ACCESS_API_KEY, - payload: "SELECT * FROM blog_posts WHERE user_id='as09d7nasd90'", -}); -``` - -You can add a condition to the `payload` object to filter the results - -```js -const datasquirel = require("datasquirel"); - -const postData = await datasquirel.post({ - key: process.env.FULL_ACCESS_API_KEY, - payload: { - action: "delete", - condition: `WHERE user_id='21adwei9jewr' AND type='buyers'`, - table: "users", - }, -}); -``` - -You can use `identifierColumnName` and `identifierValue` when updating an entry. - -```js -const datasquirel = require("datasquirel"); - -const postData = await datasquirel.post({ - key: process.env.FULL_ACCESS_API_KEY, - payload: { - action: "update", - table: "users", - identifierColumnName: "id", - identifierValue: "21adwei9jewr", - data: { - first_name: "Mary", - last_name: "Spencer", - }, - }, -}); -``` - -### Upload Image - -This method requires is similar to the `post` method, but with different parameters. - -```js -const datasquirel = require("datasquirel"); - -const postData = await datasquirel.uploadImage({ - key: process.env.FULL_ACCESS_API_KEY, - payload: { - imageData: "6ejsiua2i29ndsajkfn9n==", // Image in base64 - imageName: `awesome-waterfalls`, - mimeType: "jpg", // optional - thumbnailSize: 120, // optional === This measurement is in pixels(px) - }, -}); -``` +# Datasquirel + +This package requires an account with datasquirel, so be sure to create an account at [datasquirel-create-account](https://datasquirel.com/create-account) before you continue. + +## Instalation + +```bash +$ npm install datasquirel +``` + +Once the package is installed, you can import the library using `require` approach: + +```js +const datasquirel = require("datasquirel"); +``` + +## Usage + +### Fetch Data + +This method requires a readonly key or fullaccess API key gotten from [datasquirel](https://datasquirel.com/). It uses a basic https get request paired with some query params. + +```js +const datasquirel = require("datasquirel"); + +const getData = await datasquirel.get({ + key: "aldhkf89asdflksdafh908asdfjkhasdf", // Readonly API Key + db: "my_database", // Database name slug (Eg. Db Name => My Database, Db Slug => my_database) + query: "SELECT * FROM blog_posts", // SQL Query +}); +``` + +Datasquirel uses all conventional SQL query commands. However you can only use the `SELECT` command when using a readonly API key. + +### Post Data + +This method requires a fullaccess API key gotten from [datasquirel](https://datasquirel.com/). You can perform a basic fetch with this method, as well as more complex operations like `UPDATE`, `DELETE` and `INSERT`. + +```js +const datasquirel = require("datasquirel"); + +const postData = await datasquirel.post({ + key: "aldhkf89asdflksdafh908asdfjkhasdf", // Fullaccess API Key + payload: { + action: "insert", // OR "update" OR "delete" OR "select" + data: { + user_id: "19aisdn123", + user_first_name: "John", + user_last_name: "Doe", + }, + table: "users", + }, +}); +``` + +You can simply replace the `payload` object with an SQL string and it does everything you provide in the SQL command. + +```js +const datasquirel = require("datasquirel"); + +const postData = await datasquirel.post({ + key: process.env.FULL_ACCESS_API_KEY, + payload: "SELECT * FROM blog_posts WHERE user_id='as09d7nasd90'", +}); +``` + +You can add a condition to the `payload` object to filter the results + +```js +const datasquirel = require("datasquirel"); + +const postData = await datasquirel.post({ + key: process.env.FULL_ACCESS_API_KEY, + payload: { + action: "delete", + condition: `WHERE user_id='21adwei9jewr' AND type='buyers'`, + table: "users", + }, +}); +``` + +You can use `identifierColumnName` and `identifierValue` when updating an entry. + +```js +const datasquirel = require("datasquirel"); + +const postData = await datasquirel.post({ + key: process.env.FULL_ACCESS_API_KEY, + payload: { + action: "update", + table: "users", + identifierColumnName: "id", + identifierValue: "21adwei9jewr", + data: { + first_name: "Mary", + last_name: "Spencer", + }, + }, +}); +``` + +### Upload Image + +This method requires is similar to the `post` method, but with different parameters. + +```js +const datasquirel = require("datasquirel"); + +const postData = await datasquirel.uploadImage({ + key: process.env.FULL_ACCESS_API_KEY, + payload: { + imageData: "6ejsiua2i29ndsajkfn9n==", // Image in base64 + imageName: `awesome-waterfalls`, + mimeType: "jpg", // optional + thumbnailSize: 120, // optional === This measurement is in pixels(px) + }, +}); +``` diff --git a/client/auth/github/getAccessToken.js b/client/auth/github/getAccessToken.js index 3243265..cee9ab4 100644 --- a/client/auth/github/getAccessToken.js +++ b/client/auth/github/getAccessToken.js @@ -1,36 +1,36 @@ -// @ts-check - -/** - * Login with Github Function - * =============================================================================== - * @description This function uses github api to login a user with datasquirel - * - * @async - * - * @param {object} params - Single object passed - * @param {string} params.clientId - Github app client ID: {@link https://datasquirel.com/docs} - * @param {string} params.redirectUrl - Github Redirect URL as listed in your oauth app settings: {@link https://datasquirel.com/docs} - * @param {function(boolean): void} [params.setLoading] - React setState Function: sets whether the google login button is ready or not - * @param {string[]} [params.scopes] - Scopes to be requested from the user - * - * @returns {void} - Return - */ -module.exports = function getAccessToken({ clientId, redirectUrl, setLoading, scopes }) { - /** - * == Initialize - * - * @description Initialize - */ - if (setLoading) setLoading(true); - - const scopeString = scopes ? scopes.join("%20") : "read:user"; - const fetchUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}&scope=${scopeString}&redirect_uri=${redirectUrl}`; - window.location.assign(fetchUrl); - - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// -}; +// @ts-check + +/** + * Login with Github Function + * =============================================================================== + * @description This function uses github api to login a user with datasquirel + * + * @async + * + * @param {object} params - Single object passed + * @param {string} params.clientId - Github app client ID: {@link https://datasquirel.com/docs} + * @param {string} params.redirectUrl - Github Redirect URL as listed in your oauth app settings: {@link https://datasquirel.com/docs} + * @param {function(boolean): void} [params.setLoading] - React setState Function: sets whether the google login button is ready or not + * @param {string[]} [params.scopes] - Scopes to be requested from the user + * + * @returns {void} - Return + */ +module.exports = function getAccessToken({ clientId, redirectUrl, setLoading, scopes }) { + /** + * == Initialize + * + * @description Initialize + */ + if (setLoading) setLoading(true); + + const scopeString = scopes ? scopes.join("%20") : "read:user"; + const fetchUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}&scope=${scopeString}&redirect_uri=${redirectUrl}`; + window.location.assign(fetchUrl); + + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// +}; diff --git a/client/auth/google/getAccessToken.js b/client/auth/google/getAccessToken.js index 4e418a2..b42cefc 100644 --- a/client/auth/google/getAccessToken.js +++ b/client/auth/google/getAccessToken.js @@ -1,113 +1,113 @@ -/** - * Type Definitions - * =============================================================================== - */ - -/** - * @typedef {object} GoogleIdentityPromptNotification - * @property {function(): string} getMomentType - Notification moment type - * @property {function(): string} getDismissedReason - Notification get Dismissed Reason - * @property {function(): string} getNotDisplayedReason - Notification get Not Displayed Reason - * @property {function(): string} getSkippedReason - Notification get Skipped Reason - * @property {function(): boolean} isDismissedMoment - Notification is Dismissed Moment - * @property {function(): boolean} isDisplayMoment - Notification is Display Moment - * @property {function(): boolean} isDisplayed - Notification is Displayed - * @property {function(): boolean} isNotDisplayed - Notification is Not Displayed - * @property {function(): boolean} isSkippedMoment - Notification is Skipped Moment - */ - -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// - -/** - * Login with Google Function - * =============================================================================== - * @description This function uses google identity api to login a user with datasquirel - * - * @async - * - * @param {object} params - Single object passed - * @param {string} params.clientId - Google app client ID: {@link https://datasquirel.com/docs} - * @param {HTMLElement} params.element - HTML Element to display google login button - * @param {boolean} params.triggerPrompt - Whether to trigger Google signing popup or not: {@link https://datasquirel.com/docs} - * @param {function(): void} [params.readyStateDispatch] - React setState Function: sets whether the google login button is ready or not - * - * @returns {Promise} - Return - */ -module.exports = async function getAccessToken({ clientId, element, triggerPrompt, readyStateDispatch }) { - /** - * == Initialize - * - * @description Initialize - */ - const googleScript = document.createElement("script"); - googleScript.src = "https://accounts.google.com/gsi/client"; - googleScript.className = "social-script-tag"; - - document.body.appendChild(googleScript); - - const response = await new Promise((resolve, reject) => { - googleScript.onload = function (e) { - if (google) { - if (readyStateDispatch) readyStateDispatch(true); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - if (element) { - /** - * Handle google credentials response - * ======================================================== - * @param {object} response - Google response with credentials - * @param {string} response.credential - Google access token - */ - function handleCredentialResponse(response) { - resolve(response.credential); - } - - google.accounts.id.initialize({ - client_id: clientId, - callback: handleCredentialResponse, - }); - - google.accounts.id.renderButton(element, { - theme: "outline", - size: "large", - logo_alignment: "center", - }); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - if (triggerPrompt) { - google.accounts.id.prompt( - /** - * Google prompt notification callback - * ======================================================== - * @param {GoogleIdentityPromptNotification} notification - Notification object - */ - (notification) => { - notification.isDisplayed(); - } - ); - } - } - }; - }); - - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - - return response; -}; +/** + * Type Definitions + * =============================================================================== + */ + +/** + * @typedef {object} GoogleIdentityPromptNotification + * @property {function(): string} getMomentType - Notification moment type + * @property {function(): string} getDismissedReason - Notification get Dismissed Reason + * @property {function(): string} getNotDisplayedReason - Notification get Not Displayed Reason + * @property {function(): string} getSkippedReason - Notification get Skipped Reason + * @property {function(): boolean} isDismissedMoment - Notification is Dismissed Moment + * @property {function(): boolean} isDisplayMoment - Notification is Display Moment + * @property {function(): boolean} isDisplayed - Notification is Displayed + * @property {function(): boolean} isNotDisplayed - Notification is Not Displayed + * @property {function(): boolean} isSkippedMoment - Notification is Skipped Moment + */ + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +/** + * Login with Google Function + * =============================================================================== + * @description This function uses google identity api to login a user with datasquirel + * + * @async + * + * @param {object} params - Single object passed + * @param {string} params.clientId - Google app client ID: {@link https://datasquirel.com/docs} + * @param {HTMLElement} params.element - HTML Element to display google login button + * @param {boolean} params.triggerPrompt - Whether to trigger Google signing popup or not: {@link https://datasquirel.com/docs} + * @param {function(): void} [params.readyStateDispatch] - React setState Function: sets whether the google login button is ready or not + * + * @returns {Promise} - Return + */ +module.exports = async function getAccessToken({ clientId, element, triggerPrompt, readyStateDispatch }) { + /** + * == Initialize + * + * @description Initialize + */ + const googleScript = document.createElement("script"); + googleScript.src = "https://accounts.google.com/gsi/client"; + googleScript.className = "social-script-tag"; + + document.body.appendChild(googleScript); + + const response = await new Promise((resolve, reject) => { + googleScript.onload = function (e) { + if (google) { + if (readyStateDispatch) readyStateDispatch(true); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + if (element) { + /** + * Handle google credentials response + * ======================================================== + * @param {object} response - Google response with credentials + * @param {string} response.credential - Google access token + */ + function handleCredentialResponse(response) { + resolve(response.credential); + } + + google.accounts.id.initialize({ + client_id: clientId, + callback: handleCredentialResponse, + }); + + google.accounts.id.renderButton(element, { + theme: "outline", + size: "large", + logo_alignment: "center", + }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + if (triggerPrompt) { + google.accounts.id.prompt( + /** + * Google prompt notification callback + * ======================================================== + * @param {GoogleIdentityPromptNotification} notification - Notification object + */ + (notification) => { + notification.isDisplayed(); + } + ); + } + } + }; + }); + + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + + return response; +}; diff --git a/client/auth/logout.js b/client/auth/logout.js index ece6ee8..f5fa88c 100644 --- a/client/auth/logout.js +++ b/client/auth/logout.js @@ -1,146 +1,146 @@ -/** - * Type Definitions - * =============================================================================== - */ - -const parseClientCookies = require("../utils/parseClientCookies"); - -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// - -/** - * Login with Google Function - * =============================================================================== - * @description This function uses google identity api to login a user with datasquirel - * - * @async - * - * @param {object|null} params - Single object passed - * @param {string|null} params.googleClientId - Google client Id if applicable - * - * @requires localStorageUser - a "user" JSON string stored in local storage with all - * the necessary user data gotten from the server - * - * @returns {Promise} - Return - */ -module.exports = async function logout(params) { - /** - * == Initialize - * - * @description Initialize - */ - const localUser = localStorage.getItem("user"); - let targetUser; - - try { - targetUser = JSON.parse(localUser); - } catch (error) { - console.log(error); - } - - if (!targetUser) { - return false; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - const cookies = parseClientCookies(); - const socialId = cookies?.datasquirel_social_id && typeof cookies.datasquirel_social_id == "string" && !cookies.datasquirel_social_id.match(/^null$/i) ? cookies.datasquirel_social_id : null; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - localStorage.setItem("user", "{}"); - localStorage.removeItem("csrf"); - - document.cookie = `datasquirel_social_id=null;samesite=strict;path=/`; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - const response = await new Promise((resolve, reject) => { - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - - if (socialId && !socialId?.match(/^null$/i)) { - const googleClientId = params?.googleClientId; - - if (googleClientId) { - const googleScript = document.createElement("script"); - googleScript.src = "https://accounts.google.com/gsi/client"; - googleScript.className = "social-script-tag"; - - document.body.appendChild(googleScript); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - googleScript.onload = function (e) { - if (google) { - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - google.accounts.id.initialize({ - client_id: googleClientId, - }); - - google.accounts.id.revoke(socialId, (done) => { - console.log(done.error); - - resolve(true); - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } - }; - } else { - resolve(true); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } else { - resolve(true); - } - - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - }); - - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - - return response; - - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////// -}; +/** + * Type Definitions + * =============================================================================== + */ + +const parseClientCookies = require("../utils/parseClientCookies"); + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +/** + * Login with Google Function + * =============================================================================== + * @description This function uses google identity api to login a user with datasquirel + * + * @async + * + * @param {object|null} params - Single object passed + * @param {string|null} params.googleClientId - Google client Id if applicable + * + * @requires localStorageUser - a "user" JSON string stored in local storage with all + * the necessary user data gotten from the server + * + * @returns {Promise} - Return + */ +module.exports = async function logout(params) { + /** + * == Initialize + * + * @description Initialize + */ + const localUser = localStorage.getItem("user"); + let targetUser; + + try { + targetUser = JSON.parse(localUser); + } catch (error) { + console.log(error); + } + + if (!targetUser) { + return false; + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + const cookies = parseClientCookies(); + const socialId = cookies?.datasquirel_social_id && typeof cookies.datasquirel_social_id == "string" && !cookies.datasquirel_social_id.match(/^null$/i) ? cookies.datasquirel_social_id : null; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + localStorage.setItem("user", "{}"); + localStorage.removeItem("csrf"); + + document.cookie = `datasquirel_social_id=null;samesite=strict;path=/`; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + const response = await new Promise((resolve, reject) => { + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + + if (socialId && !socialId?.match(/^null$/i)) { + const googleClientId = params?.googleClientId; + + if (googleClientId) { + const googleScript = document.createElement("script"); + googleScript.src = "https://accounts.google.com/gsi/client"; + googleScript.className = "social-script-tag"; + + document.body.appendChild(googleScript); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + googleScript.onload = function (e) { + if (google) { + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + google.accounts.id.initialize({ + client_id: googleClientId, + }); + + google.accounts.id.revoke(socialId, (done) => { + console.log(done.error); + + resolve(true); + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } + }; + } else { + resolve(true); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } else { + resolve(true); + } + + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + }); + + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + + return response; + + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// +}; diff --git a/client/index.js b/client/index.js index 34ff5bd..0aad182 100644 --- a/client/index.js +++ b/client/index.js @@ -1,47 +1,47 @@ -// @ts-check - -/** - * Imports - */ -const imageInputFileToBase64 = require("./media/imageInputFileToBase64"); -const imageInputToBase64 = require("./media/imageInputToBase64"); -const inputFileToBase64 = require("./media/inputFileToBase64"); -const getAccessToken = require("./auth/google/getAccessToken"); -const getGithubAccessToken = require("./auth/github/getAccessToken"); -const logout = require("./auth/logout"); - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -/** - * Media Functions Object - */ -const media = { - imageInputToBase64: imageInputToBase64, - imageInputFileToBase64: imageInputFileToBase64, - inputFileToBase64: inputFileToBase64, -}; - -/** - * User Auth Object - */ -const auth = { - google: { - getAccessToken: getAccessToken, - }, - github: { - getAccessToken: getGithubAccessToken, - }, - logout: logout, -}; - -/** - * Main Export - */ -const datasquirelClient = { - media: media, - auth: auth, -}; - -module.exports = datasquirelClient; +// @ts-check + +/** + * Imports + */ +const imageInputFileToBase64 = require("./media/imageInputFileToBase64"); +const imageInputToBase64 = require("./media/imageInputToBase64"); +const inputFileToBase64 = require("./media/inputFileToBase64"); +const getAccessToken = require("./auth/google/getAccessToken"); +const getGithubAccessToken = require("./auth/github/getAccessToken"); +const logout = require("./auth/logout"); + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +/** + * Media Functions Object + */ +const media = { + imageInputToBase64: imageInputToBase64, + imageInputFileToBase64: imageInputFileToBase64, + inputFileToBase64: inputFileToBase64, +}; + +/** + * User Auth Object + */ +const auth = { + google: { + getAccessToken: getAccessToken, + }, + github: { + getAccessToken: getGithubAccessToken, + }, + logout: logout, +}; + +/** + * Main Export + */ +const datasquirelClient = { + media: media, + auth: auth, +}; + +module.exports = datasquirelClient; diff --git a/client/media/client.js b/client/media/client.js index 39ef7f5..72f7431 100644 --- a/client/media/client.js +++ b/client/media/client.js @@ -1,49 +1,49 @@ -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -import imageInputFileToBase64 from "./imageInputFileToBase64"; -import imageInputToBase64 from "./imageInputToBase64"; - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * ============================================================================== - * Media Functions Object - * ============================================================================== - */ -const media = { - imageInputToBase64: imageInputToBase64, - imageInputFileToBase64: imageInputFileToBase64, -}; - -/** - * ============================================================================== - * Media Functions Object - * ============================================================================== - */ -const auth = { - imageInputToBase64: imageInputToBase64, - imageInputFileToBase64: imageInputFileToBase64, -}; - -/** - * ============================================================================== - * Main Export - * ============================================================================== - */ -const datasquirelClient = { - media: media, -}; - -export default datasquirelClient; - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +import imageInputFileToBase64 from "./imageInputFileToBase64"; +import imageInputToBase64 from "./imageInputToBase64"; + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * ============================================================================== + * Media Functions Object + * ============================================================================== + */ +const media = { + imageInputToBase64: imageInputToBase64, + imageInputFileToBase64: imageInputFileToBase64, +}; + +/** + * ============================================================================== + * Media Functions Object + * ============================================================================== + */ +const auth = { + imageInputToBase64: imageInputToBase64, + imageInputFileToBase64: imageInputFileToBase64, +}; + +/** + * ============================================================================== + * Main Export + * ============================================================================== + */ +const datasquirelClient = { + media: media, +}; + +export default datasquirelClient; + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ diff --git a/client/media/imageInputFileToBase64.js b/client/media/imageInputFileToBase64.js index 508c807..e17ba1d 100644 --- a/client/media/imageInputFileToBase64.js +++ b/client/media/imageInputFileToBase64.js @@ -1,111 +1,111 @@ -/** - * @typedef {{ - * imageBase64: string, - * imageBase64Full: string, - * imageName: string, - * imageSize: number, - * }} FunctionReturn - */ - -/** - * ============================================================================== - * Main Function - * ============================================================================== - * @async - * - * @param {{ - * imageInputFile: { name:string }, - * maxWidth: number, - * imagePreviewNode: HTMLImageElement, - * }} params - Single object passed - * - * @returns { Promise } - Return Object - */ -module.exports = async function imageInputFileToBase64({ imageInputFile, maxWidth, imagePreviewNode }) { - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - try { - let imageName = imageInputFile.name.replace(/\..*/, ""); - let imageDataBase64; - let imageSize; - let canvas = document.createElement("canvas"); - - const MIME_TYPE = imageInputFile.type; - const QUALITY = 0.95; - const MAX_WIDTH = maxWidth ? maxWidth : null; - - const file = imageInputFile; // get the file - const blobURL = URL.createObjectURL(file); - const img = new Image(); - - /** ********************* Add source to new image */ - img.src = blobURL; - - imageDataBase64 = await new Promise((res, rej) => { - /** ********************* Handle Errors in loading image */ - img.onerror = function () { - URL.revokeObjectURL(this.src); - console.log("Cannot load image"); - }; - - /** ********************* Handle new image when loaded */ - img.onload = function () { - URL.revokeObjectURL(this.src); - - if (MAX_WIDTH) { - const scaleSize = MAX_WIDTH / img.naturalWidth; - - canvas.width = img.naturalWidth < MAX_WIDTH ? img.naturalWidth : MAX_WIDTH; - canvas.height = img.naturalWidth < MAX_WIDTH ? img.naturalHeight : img.naturalHeight * scaleSize; - } else { - canvas.width = img.naturalWidth; - canvas.height = img.naturalHeight; - } - - const ctx = canvas.getContext("2d"); - ctx.drawImage(img, 0, 0, canvas.width, canvas.height); - - const srcEncoded = canvas.toDataURL(MIME_TYPE, QUALITY); - - if (imagePreviewNode) { - imagePreviewNode.src = srcEncoded; - } - - res(srcEncoded); - }; - }); - - imageSize = await new Promise((res, rej) => { - canvas.toBlob( - (blob) => { - res(blob.size); - }, - MIME_TYPE, - QUALITY - ); - }); - - return { - imageBase64: imageDataBase64.replace(/.*?base64,/, ""), - imageBase64Full: imageDataBase64, - imageName: imageName, - imageSize: imageSize, - }; - } catch (/** @type {*} */ error) { - console.log("Image Processing Error! =>", error.message); - - return { - imageBase64: null, - imageBase64Full: null, - imageName: null, - imageSize: null, - }; - } -}; - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ +/** + * @typedef {{ + * imageBase64: string, + * imageBase64Full: string, + * imageName: string, + * imageSize: number, + * }} FunctionReturn + */ + +/** + * ============================================================================== + * Main Function + * ============================================================================== + * @async + * + * @param {{ + * imageInputFile: { name:string }, + * maxWidth: number, + * imagePreviewNode: HTMLImageElement, + * }} params - Single object passed + * + * @returns { Promise } - Return Object + */ +module.exports = async function imageInputFileToBase64({ imageInputFile, maxWidth, imagePreviewNode }) { + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + try { + let imageName = imageInputFile.name.replace(/\..*/, ""); + let imageDataBase64; + let imageSize; + let canvas = document.createElement("canvas"); + + const MIME_TYPE = imageInputFile.type; + const QUALITY = 0.95; + const MAX_WIDTH = maxWidth ? maxWidth : null; + + const file = imageInputFile; // get the file + const blobURL = URL.createObjectURL(file); + const img = new Image(); + + /** ********************* Add source to new image */ + img.src = blobURL; + + imageDataBase64 = await new Promise((res, rej) => { + /** ********************* Handle Errors in loading image */ + img.onerror = function () { + URL.revokeObjectURL(this.src); + console.log("Cannot load image"); + }; + + /** ********************* Handle new image when loaded */ + img.onload = function () { + URL.revokeObjectURL(this.src); + + if (MAX_WIDTH) { + const scaleSize = MAX_WIDTH / img.naturalWidth; + + canvas.width = img.naturalWidth < MAX_WIDTH ? img.naturalWidth : MAX_WIDTH; + canvas.height = img.naturalWidth < MAX_WIDTH ? img.naturalHeight : img.naturalHeight * scaleSize; + } else { + canvas.width = img.naturalWidth; + canvas.height = img.naturalHeight; + } + + const ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0, canvas.width, canvas.height); + + const srcEncoded = canvas.toDataURL(MIME_TYPE, QUALITY); + + if (imagePreviewNode) { + imagePreviewNode.src = srcEncoded; + } + + res(srcEncoded); + }; + }); + + imageSize = await new Promise((res, rej) => { + canvas.toBlob( + (blob) => { + res(blob.size); + }, + MIME_TYPE, + QUALITY + ); + }); + + return { + imageBase64: imageDataBase64.replace(/.*?base64,/, ""), + imageBase64Full: imageDataBase64, + imageName: imageName, + imageSize: imageSize, + }; + } catch (/** @type {*} */ error) { + console.log("Image Processing Error! =>", error.message); + + return { + imageBase64: null, + imageBase64Full: null, + imageName: null, + imageSize: null, + }; + } +}; + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ diff --git a/client/media/imageInputToBase64.js b/client/media/imageInputToBase64.js index 3932fea..adebad9 100644 --- a/client/media/imageInputToBase64.js +++ b/client/media/imageInputToBase64.js @@ -1,101 +1,101 @@ -/** - * @typedef {{ - * imageBase64: string, - * imageBase64Full: string, - * imageName: string, - * }} FunctionReturn - */ - -/** - * ============================================================================== - * Main Function - * ============================================================================== - * @async - * - * @param {{ - * imageInput: HTMLInputElement, - * maxWidth: number, - * mimeType: [string='image/jpeg'] - * }} params - Single object passed - * - * @returns { Promise } - Return Object - */ -module.exports = async function imageInputToBase64({ imageInput, maxWidth, mimeType }) { - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - try { - let imagePreviewNode = document.querySelector(`[data-imagepreview='image']`); - let imageName = imageInput.files[0].name.replace(/\..*/, ""); - let imageDataBase64; - - const MIME_TYPE = mimeType ? mimeType : "image/jpeg"; - const QUALITY = 0.95; - const MAX_WIDTH = maxWidth ? maxWidth : null; - - const file = imageInput.files[0]; // get the file - const blobURL = URL.createObjectURL(file); - const img = new Image(); - - /** ********************* Add source to new image */ - img.src = blobURL; - - imageDataBase64 = await new Promise((res, rej) => { - /** ********************* Handle Errors in loading image */ - img.onerror = function () { - URL.revokeObjectURL(this.src); - window.alert("Cannot load image!"); - }; - - /** ********************* Handle new image when loaded */ - img.onload = function () { - URL.revokeObjectURL(this.src); - - const canvas = document.createElement("canvas"); - - if (MAX_WIDTH) { - const scaleSize = MAX_WIDTH / img.naturalWidth; - - canvas.width = img.naturalWidth < MAX_WIDTH ? img.naturalWidth : MAX_WIDTH; - canvas.height = img.naturalWidth < MAX_WIDTH ? img.naturalHeight : img.naturalHeight * scaleSize; - } else { - canvas.width = img.naturalWidth; - canvas.height = img.naturalHeight; - } - - const ctx = canvas.getContext("2d"); - ctx.drawImage(img, 0, 0, canvas.width, canvas.height); - - const srcEncoded = canvas.toDataURL(MIME_TYPE, QUALITY); - - if (imagePreviewNode) { - document.querySelectorAll(`[data-imagepreview='image']`).forEach((img) => { - img.src = srcEncoded; - }); - } - - res(srcEncoded); - }; - }); - - return { - imageBase64: imageDataBase64.replace(/.*?base64,/, ""), - imageBase64Full: imageDataBase64, - imageName: imageName, - }; - } catch (/** @type {*} */ error) { - console.log("Image Processing Error! =>", error.message); - - return { - imageBase64: null, - imageBase64Full: null, - imageName: null, - }; - } -}; - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ +/** + * @typedef {{ + * imageBase64: string, + * imageBase64Full: string, + * imageName: string, + * }} FunctionReturn + */ + +/** + * ============================================================================== + * Main Function + * ============================================================================== + * @async + * + * @param {{ + * imageInput: HTMLInputElement, + * maxWidth: number, + * mimeType: [string='image/jpeg'] + * }} params - Single object passed + * + * @returns { Promise } - Return Object + */ +module.exports = async function imageInputToBase64({ imageInput, maxWidth, mimeType }) { + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + try { + let imagePreviewNode = document.querySelector(`[data-imagepreview='image']`); + let imageName = imageInput.files[0].name.replace(/\..*/, ""); + let imageDataBase64; + + const MIME_TYPE = mimeType ? mimeType : "image/jpeg"; + const QUALITY = 0.95; + const MAX_WIDTH = maxWidth ? maxWidth : null; + + const file = imageInput.files[0]; // get the file + const blobURL = URL.createObjectURL(file); + const img = new Image(); + + /** ********************* Add source to new image */ + img.src = blobURL; + + imageDataBase64 = await new Promise((res, rej) => { + /** ********************* Handle Errors in loading image */ + img.onerror = function () { + URL.revokeObjectURL(this.src); + window.alert("Cannot load image!"); + }; + + /** ********************* Handle new image when loaded */ + img.onload = function () { + URL.revokeObjectURL(this.src); + + const canvas = document.createElement("canvas"); + + if (MAX_WIDTH) { + const scaleSize = MAX_WIDTH / img.naturalWidth; + + canvas.width = img.naturalWidth < MAX_WIDTH ? img.naturalWidth : MAX_WIDTH; + canvas.height = img.naturalWidth < MAX_WIDTH ? img.naturalHeight : img.naturalHeight * scaleSize; + } else { + canvas.width = img.naturalWidth; + canvas.height = img.naturalHeight; + } + + const ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0, canvas.width, canvas.height); + + const srcEncoded = canvas.toDataURL(MIME_TYPE, QUALITY); + + if (imagePreviewNode) { + document.querySelectorAll(`[data-imagepreview='image']`).forEach((img) => { + img.src = srcEncoded; + }); + } + + res(srcEncoded); + }; + }); + + return { + imageBase64: imageDataBase64.replace(/.*?base64,/, ""), + imageBase64Full: imageDataBase64, + imageName: imageName, + }; + } catch (/** @type {*} */ error) { + console.log("Image Processing Error! =>", error.message); + + return { + imageBase64: null, + imageBase64Full: null, + imageName: null, + }; + } +}; + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ diff --git a/client/media/inputFileToBase64.js b/client/media/inputFileToBase64.js index af97614..9927707 100644 --- a/client/media/inputFileToBase64.js +++ b/client/media/inputFileToBase64.js @@ -1,96 +1,96 @@ -/** - * @typedef {{ - * fileBase64: string, - * fileBase64Full: string, - * fileName: string, - * fileSize: number, - * fileType: string, - * }} FunctionReturn - */ - -/** - * Input File to base64 - * ============================================================================== - * - * @description This function takes in a *SINGLE* input file from a HTML file input element. - * HTML file input elements usually return an array of input objects, so be sure to select the target - * file from the array. - * - * @async - * - * @param {object} params - Single object passed - * @param {object} params.inputFile - HTML input File - * @param {string} params.inputFile.name - Input File Name - * @param {number} params.inputFile.size - Input File Size in bytes - * @param {string} params.inputFile.type - Input File Type: "JPEG", "PNG", "PDF", etc. Whichever allowed regexp is provided - * @param {RegExp} [params.allowedRegex] - Regexp containing the allowed file types - * - * @returns { Promise } - Return Object - */ -module.exports = async function inputFileToBase64({ inputFile, allowedRegex }) { - /** - * == Initialize - * - * @description Initialize - */ - const allowedTypesRegex = allowedRegex ? allowedRegex : /image\/*|\/pdf/; - - if (!inputFile?.type?.match(allowedTypesRegex)) { - window.alert(`We currently don't support ${inputFile.type} file types. Support is coming soon. For now we support only images and PDFs.`); - - return { - fileBase64: null, - fileBase64Full: null, - fileName: inputFile.name, - fileSize: null, - fileType: null, - }; - } - - try { - /** Process File **/ - let fileName = inputFile.name.replace(/\..*/, ""); - - /** Add source to new file **/ - const fileData = await new Promise((resolve, reject) => { - var reader = new FileReader(); - reader.readAsDataURL(inputFile); - reader.onload = function () { - resolve(reader.result); - }; - reader.onerror = function (/** @type {*} */ error) { - console.log("Error: ", error.message); - }; - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - return { - fileBase64: fileData.replace(/.*?base64,/, ""), - fileBase64Full: fileData, - fileName: fileName, - fileSize: inputFile.size, - fileType: inputFile.type, - }; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("File Processing Error! =>", error.message); - - return { - fileBase64: null, - fileBase64Full: null, - fileName: inputFile.name, - fileSize: null, - fileType: null, - }; - } -}; - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// +/** + * @typedef {{ + * fileBase64: string, + * fileBase64Full: string, + * fileName: string, + * fileSize: number, + * fileType: string, + * }} FunctionReturn + */ + +/** + * Input File to base64 + * ============================================================================== + * + * @description This function takes in a *SINGLE* input file from a HTML file input element. + * HTML file input elements usually return an array of input objects, so be sure to select the target + * file from the array. + * + * @async + * + * @param {object} params - Single object passed + * @param {object} params.inputFile - HTML input File + * @param {string} params.inputFile.name - Input File Name + * @param {number} params.inputFile.size - Input File Size in bytes + * @param {string} params.inputFile.type - Input File Type: "JPEG", "PNG", "PDF", etc. Whichever allowed regexp is provided + * @param {RegExp} [params.allowedRegex] - Regexp containing the allowed file types + * + * @returns { Promise } - Return Object + */ +module.exports = async function inputFileToBase64({ inputFile, allowedRegex }) { + /** + * == Initialize + * + * @description Initialize + */ + const allowedTypesRegex = allowedRegex ? allowedRegex : /image\/*|\/pdf/; + + if (!inputFile?.type?.match(allowedTypesRegex)) { + window.alert(`We currently don't support ${inputFile.type} file types. Support is coming soon. For now we support only images and PDFs.`); + + return { + fileBase64: null, + fileBase64Full: null, + fileName: inputFile.name, + fileSize: null, + fileType: null, + }; + } + + try { + /** Process File **/ + let fileName = inputFile.name.replace(/\..*/, ""); + + /** Add source to new file **/ + const fileData = await new Promise((resolve, reject) => { + var reader = new FileReader(); + reader.readAsDataURL(inputFile); + reader.onload = function () { + resolve(reader.result); + }; + reader.onerror = function (/** @type {*} */ error) { + console.log("Error: ", error.message); + }; + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + return { + fileBase64: fileData.replace(/.*?base64,/, ""), + fileBase64Full: fileData, + fileName: fileName, + fileSize: inputFile.size, + fileType: inputFile.type, + }; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } catch (/** @type {*} */ error) { + console.log("File Processing Error! =>", error.message); + + return { + fileBase64: null, + fileBase64Full: null, + fileName: inputFile.name, + fileSize: null, + fileType: null, + }; + } +}; + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// diff --git a/client/utils/parseClientCookies.js b/client/utils/parseClientCookies.js index 5938f96..7b7eb70 100644 --- a/client/utils/parseClientCookies.js +++ b/client/utils/parseClientCookies.js @@ -1,65 +1,65 @@ -/** - * ============================================================================== - * Imports - * ============================================================================== - */ - -/** - * Parse request cookies - * ============================================================================== - * - * @description This function takes in a request object and returns the cookies as a JS object - * - * @async - * - * @param {object} params - main params object - * @param {object} params.request - HTTPS request object - * - * @returns {{}|null} - */ -module.exports = function () { - /** - * Check inputs - * - * @description Check inputs - */ - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** @type {string|null} */ - const cookieString = document.cookie; - - if (!cookieString || typeof cookieString !== "string") { - return null; - } - - /** @type {string[]} */ - const cookieSplitArray = cookieString.split(";"); - - let cookieObject = {}; - - cookieSplitArray.forEach((keyValueString) => { - const [key, value] = keyValueString.split("="); - if (key && typeof key == "string") { - cookieObject[key.replace(/^ +| +$/, "")] = value && typeof value == "string" ? value.replace(/^ +| +$/, "") : null; - } - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - - return cookieObject; -}; - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// +/** + * ============================================================================== + * Imports + * ============================================================================== + */ + +/** + * Parse request cookies + * ============================================================================== + * + * @description This function takes in a request object and returns the cookies as a JS object + * + * @async + * + * @param {object} params - main params object + * @param {object} params.request - HTTPS request object + * + * @returns {{}|null} + */ +module.exports = function () { + /** + * Check inputs + * + * @description Check inputs + */ + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** @type {string|null} */ + const cookieString = document.cookie; + + if (!cookieString || typeof cookieString !== "string") { + return null; + } + + /** @type {string[]} */ + const cookieSplitArray = cookieString.split(";"); + + let cookieObject = {}; + + cookieSplitArray.forEach((keyValueString) => { + const [key, value] = keyValueString.split("="); + if (key && typeof key == "string") { + cookieObject[key.replace(/^ +| +$/, "")] = value && typeof value == "string" ? value.replace(/^ +| +$/, "") : null; + } + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + + return cookieObject; +}; + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// diff --git a/console-colors.js b/console-colors.js index bec5d22..708acf6 100644 --- a/console-colors.js +++ b/console-colors.js @@ -1,31 +1,31 @@ -const colors = { - Reset: "\x1b[0m", - Bright: "\x1b[1m", - Dim: "\x1b[2m", - Underscore: "\x1b[4m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - Hidden: "\x1b[8m", - - FgBlack: "\x1b[30m", - FgRed: "\x1b[31m", - FgGreen: "\x1b[32m", - FgYellow: "\x1b[33m", - FgBlue: "\x1b[34m", - FgMagenta: "\x1b[35m", - FgCyan: "\x1b[36m", - FgWhite: "\x1b[37m", - FgGray: "\x1b[90m", - - BgBlack: "\x1b[40m", - BgRed: "\x1b[41m", - BgGreen: "\x1b[42m", - BgYellow: "\x1b[43m", - BgBlue: "\x1b[44m", - BgMagenta: "\x1b[45m", - BgCyan: "\x1b[46m", - BgWhite: "\x1b[47m", - BgGray: "\x1b[100m", -}; - -module.exports = colors; +const colors = { + Reset: "\x1b[0m", + Bright: "\x1b[1m", + Dim: "\x1b[2m", + Underscore: "\x1b[4m", + Blink: "\x1b[5m", + Reverse: "\x1b[7m", + Hidden: "\x1b[8m", + + FgBlack: "\x1b[30m", + FgRed: "\x1b[31m", + FgGreen: "\x1b[32m", + FgYellow: "\x1b[33m", + FgBlue: "\x1b[34m", + FgMagenta: "\x1b[35m", + FgCyan: "\x1b[36m", + FgWhite: "\x1b[37m", + FgGray: "\x1b[90m", + + BgBlack: "\x1b[40m", + BgRed: "\x1b[41m", + BgGreen: "\x1b[42m", + BgYellow: "\x1b[43m", + BgBlue: "\x1b[44m", + BgMagenta: "\x1b[45m", + BgCyan: "\x1b[46m", + BgWhite: "\x1b[47m", + BgGray: "\x1b[100m", +}; + +module.exports = colors; diff --git a/engine/dsql.js b/engine/dsql.js index aa1ba20..bac7aae 100644 --- a/engine/dsql.js +++ b/engine/dsql.js @@ -1,116 +1,116 @@ -#! /usr/bin/env node -// @ts-check - -const fs = require("fs"); -const path = require("path"); -const { execSync } = require("child_process"); - -require("dotenv").config({ - path: path.resolve(process.cwd(), ".env"), -}); - -const datasquirel = require("../index"); -const createDbFromSchema = require("./engine/createDbFromSchema"); -const colors = require("../console-colors"); - -if (!fs.existsSync(path.resolve(process.cwd(), ".env"))) { - console.log(".env file not found"); - process.exit(); -} - -const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME, DSQL_KEY, DSQL_REF_DB_NAME, DSQL_FULL_SYNC, DSQL_ENCRYPTION_KEY, DSQL_ENCRYPTION_SALT } = process.env; - -if (!DSQL_HOST?.match(/./)) { - console.log("DSQL_HOST is required in your `.env` file"); - process.exit(); -} - -if (!DSQL_USER?.match(/./)) { - console.log("DSQL_USER is required in your `.env` file"); - process.exit(); -} - -if (!DSQL_PASS?.match(/./)) { - console.log("DSQL_PASS is required in your `.env` file"); - process.exit(); -} - -const dbSchemaLocalFilePath = path.resolve(process.cwd(), "dsql.schema.json"); - -async function run() { - let schemaData; - - if (DSQL_KEY && DSQL_REF_DB_NAME?.match(/./)) { - const dbSchemaDataResponse = await datasquirel.getSchema({ - key: DSQL_KEY, - database: DSQL_REF_DB_NAME || undefined, - }); - - if (!dbSchemaDataResponse.payload || Array.isArray(dbSchemaDataResponse.payload)) { - console.log("DSQL_KEY+DSQL_REF_DB_NAME => Error in fetching DB schema"); - console.log(dbSchemaDataResponse); - process.exit(); - } - - let fetchedDbSchemaObject = dbSchemaDataResponse.payload; - if (DSQL_DB_NAME) fetchedDbSchemaObject.dbFullName = DSQL_DB_NAME; - - schemaData = [fetchedDbSchemaObject]; - } else if (DSQL_KEY) { - const dbSchemaDataResponse = await datasquirel.getSchema({ - key: DSQL_KEY, - database: DSQL_REF_DB_NAME || undefined, - }); - - if (!dbSchemaDataResponse.payload || !Array.isArray(dbSchemaDataResponse.payload)) { - console.log("DSQL_KEY => Error in fetching DB schema"); - console.log(dbSchemaDataResponse); - process.exit(); - } - - let fetchedDbSchemaObject = dbSchemaDataResponse.payload; - // fetchedDbSchemaObject.forEach((db, index) => { - // db.dbFullName = db.dbFullName?.replace(/^datasquirel_user_\d+_/, ""); - // }); - - schemaData = fetchedDbSchemaObject; - } else if (fs.existsSync(dbSchemaLocalFilePath)) { - schemaData = [JSON.parse(fs.readFileSync(dbSchemaLocalFilePath, "utf8"))]; - } else { - console.log("No source for DB Schema. Please provide a local `dsql.schema.json` file, or provide `DSQL_KEY` and `DSQL_REF_DB_NAME` environment variables."); - process.exit(); - } - - if (!schemaData) { - console.log("No schema found"); - process.exit(); - } - - if (DSQL_FULL_SYNC?.match(/true/i)) { - fs.writeFileSync(dbSchemaLocalFilePath, JSON.stringify(schemaData[0], null, 4), "utf8"); - } - - console.log(` - ${colors.FgBlue}Info:${colors.Reset} Now generating and mapping databases ...`); - - // deepcode ignore reDOS: - await createDbFromSchema(schemaData); - console.log(` - ${colors.FgGreen}Success:${colors.Reset} Databases created Successfully!`); -} - -// let timeout; - -let interval; - -if (fs.existsSync(dbSchemaLocalFilePath) && !DSQL_KEY?.match(/....../)) { - fs.watchFile(dbSchemaLocalFilePath, { interval: 1000 }, (curr, prev) => { - console.log(` - ${colors.FgBlue}Info:${colors.Reset} Syncing Databases Locally ...`); - run(); - }); -} else if (DSQL_KEY?.match(/....../)) { - interval = setInterval(() => { - console.log(` - ${colors.FgMagenta}Info:${colors.Reset} Syncing Databases from the cloud ...`); - run(); - }, 20000); -} - -run(); +#! /usr/bin/env node +// @ts-check + +const fs = require("fs"); +const path = require("path"); +const { execSync } = require("child_process"); + +require("dotenv").config({ + path: path.resolve(process.cwd(), ".env"), +}); + +const datasquirel = require("../index"); +const createDbFromSchema = require("./engine/createDbFromSchema"); +const colors = require("../console-colors"); + +if (!fs.existsSync(path.resolve(process.cwd(), ".env"))) { + console.log(".env file not found"); + process.exit(); +} + +const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME, DSQL_KEY, DSQL_REF_DB_NAME, DSQL_FULL_SYNC, DSQL_ENCRYPTION_KEY, DSQL_ENCRYPTION_SALT } = process.env; + +if (!DSQL_HOST?.match(/./)) { + console.log("DSQL_HOST is required in your `.env` file"); + process.exit(); +} + +if (!DSQL_USER?.match(/./)) { + console.log("DSQL_USER is required in your `.env` file"); + process.exit(); +} + +if (!DSQL_PASS?.match(/./)) { + console.log("DSQL_PASS is required in your `.env` file"); + process.exit(); +} + +const dbSchemaLocalFilePath = path.resolve(process.cwd(), "dsql.schema.json"); + +async function run() { + let schemaData; + + if (DSQL_KEY && DSQL_REF_DB_NAME?.match(/./)) { + const dbSchemaDataResponse = await datasquirel.getSchema({ + key: DSQL_KEY, + database: DSQL_REF_DB_NAME || undefined, + }); + + if (!dbSchemaDataResponse.payload || Array.isArray(dbSchemaDataResponse.payload)) { + console.log("DSQL_KEY+DSQL_REF_DB_NAME => Error in fetching DB schema"); + console.log(dbSchemaDataResponse); + process.exit(); + } + + let fetchedDbSchemaObject = dbSchemaDataResponse.payload; + if (DSQL_DB_NAME) fetchedDbSchemaObject.dbFullName = DSQL_DB_NAME; + + schemaData = [fetchedDbSchemaObject]; + } else if (DSQL_KEY) { + const dbSchemaDataResponse = await datasquirel.getSchema({ + key: DSQL_KEY, + database: DSQL_REF_DB_NAME || undefined, + }); + + if (!dbSchemaDataResponse.payload || !Array.isArray(dbSchemaDataResponse.payload)) { + console.log("DSQL_KEY => Error in fetching DB schema"); + console.log(dbSchemaDataResponse); + process.exit(); + } + + let fetchedDbSchemaObject = dbSchemaDataResponse.payload; + // fetchedDbSchemaObject.forEach((db, index) => { + // db.dbFullName = db.dbFullName?.replace(/^datasquirel_user_\d+_/, ""); + // }); + + schemaData = fetchedDbSchemaObject; + } else if (fs.existsSync(dbSchemaLocalFilePath)) { + schemaData = [JSON.parse(fs.readFileSync(dbSchemaLocalFilePath, "utf8"))]; + } else { + console.log("No source for DB Schema. Please provide a local `dsql.schema.json` file, or provide `DSQL_KEY` and `DSQL_REF_DB_NAME` environment variables."); + process.exit(); + } + + if (!schemaData) { + console.log("No schema found"); + process.exit(); + } + + if (DSQL_FULL_SYNC?.match(/true/i)) { + fs.writeFileSync(dbSchemaLocalFilePath, JSON.stringify(schemaData[0], null, 4), "utf8"); + } + + console.log(` - ${colors.FgBlue}Info:${colors.Reset} Now generating and mapping databases ...`); + + // deepcode ignore reDOS: + await createDbFromSchema(schemaData); + console.log(` - ${colors.FgGreen}Success:${colors.Reset} Databases created Successfully!`); +} + +// let timeout; + +let interval; + +if (fs.existsSync(dbSchemaLocalFilePath) && !DSQL_KEY?.match(/....../)) { + fs.watchFile(dbSchemaLocalFilePath, { interval: 1000 }, (curr, prev) => { + console.log(` - ${colors.FgBlue}Info:${colors.Reset} Syncing Databases Locally ...`); + run(); + }); +} else if (DSQL_KEY?.match(/....../)) { + interval = setInterval(() => { + console.log(` - ${colors.FgMagenta}Info:${colors.Reset} Syncing Databases from the cloud ...`); + run(); + }, 20000); +} + +run(); diff --git a/engine/dump.js b/engine/dump.js index 68eacd4..1ff8fd6 100644 --- a/engine/dump.js +++ b/engine/dump.js @@ -1,53 +1,53 @@ -#! /usr/bin/env node -// @ts-check - -const fs = require("fs"); -const path = require("path"); -const { execSync } = require("child_process"); - -require("dotenv").config({ - path: path.resolve(process.cwd(), ".env"), -}); - -const mysqlPath = process.platform?.match(/win/i) ? "'" + "C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin\\mysql.exe" + "'" : "mysql"; -const mysqlDumpPath = process.platform?.match(/win/i) ? "'" + "C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin\\mysqldump.exe" + "'" : "mysqldump"; - -const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME, DSQL_KEY, DSQL_REF_DB_NAME, DSQL_FULL_SYNC, DSQL_ENCRYPTION_KEY, DSQL_ENCRYPTION_SALT } = process.env; - -const dbName = DSQL_DB_NAME || ""; -const dumpFilePathArg = process.argv.indexOf("--file"); - -if (dumpFilePathArg < 0) { - console.log("Please provide a dump file path using `--file` argument"); - process.exit(); -} - -const dumpFilePath = process.argv[dumpFilePathArg + 1]; - -if (!dbName?.match(/./)) { - console.log("DSQL_DB_NAME is required in your `.env` file"); - process.exit(); -} - -if (!DSQL_USER?.match(/./) || !DSQL_PASS?.match(/./)) { - console.log("DSQL_USER and DSQL_PASS are required in your `.env` file"); - process.exit(); -} - -try { - let execSyncOptions = { - cwd: process.cwd(), - }; - - if (process.platform.match(/win/i)) execSyncOptions.shell = "bash.exe"; - - const dump = execSync(`${mysqlPath} -u ${DSQL_USER} -p${DSQL_PASS} ${dbName} < ${dumpFilePath}`, execSyncOptions); - - console.log("Dumped successfully", dump.toString()); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// -} catch (/** @type {*} */ error) { - console.log("Dump Error: ", error.message); -} +#! /usr/bin/env node +// @ts-check + +const fs = require("fs"); +const path = require("path"); +const { execSync } = require("child_process"); + +require("dotenv").config({ + path: path.resolve(process.cwd(), ".env"), +}); + +const mysqlPath = process.platform?.match(/win/i) ? "'" + "C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin\\mysql.exe" + "'" : "mysql"; +const mysqlDumpPath = process.platform?.match(/win/i) ? "'" + "C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin\\mysqldump.exe" + "'" : "mysqldump"; + +const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME, DSQL_KEY, DSQL_REF_DB_NAME, DSQL_FULL_SYNC, DSQL_ENCRYPTION_KEY, DSQL_ENCRYPTION_SALT } = process.env; + +const dbName = DSQL_DB_NAME || ""; +const dumpFilePathArg = process.argv.indexOf("--file"); + +if (dumpFilePathArg < 0) { + console.log("Please provide a dump file path using `--file` argument"); + process.exit(); +} + +const dumpFilePath = process.argv[dumpFilePathArg + 1]; + +if (!dbName?.match(/./)) { + console.log("DSQL_DB_NAME is required in your `.env` file"); + process.exit(); +} + +if (!DSQL_USER?.match(/./) || !DSQL_PASS?.match(/./)) { + console.log("DSQL_USER and DSQL_PASS are required in your `.env` file"); + process.exit(); +} + +try { + let execSyncOptions = { + cwd: process.cwd(), + }; + + if (process.platform.match(/win/i)) execSyncOptions.shell = "bash.exe"; + + const dump = execSync(`${mysqlPath} -u ${DSQL_USER} -p${DSQL_PASS} ${dbName} < ${dumpFilePath}`, execSyncOptions); + + console.log("Dumped successfully", dump.toString()); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// +} catch (/** @type {*} */ error) { + console.log("Dump Error: ", error.message); +} diff --git a/engine/engine/addUsersTableToDb.js b/engine/engine/addUsersTableToDb.js index 1d7ced6..bd49223 100644 --- a/engine/engine/addUsersTableToDb.js +++ b/engine/engine/addUsersTableToDb.js @@ -1,77 +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 (/** @type {*} */ error) { - console.log(error.message); - } -}; - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// +// @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 (/** @type {*} */ error) { + console.log(error.message); + } +}; + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// diff --git a/engine/engine/createDbFromSchema.js b/engine/engine/createDbFromSchema.js index e16be31..3a2eab5 100644 --- a/engine/engine/createDbFromSchema.js +++ b/engine/engine/createDbFromSchema.js @@ -1,257 +1,257 @@ -// @ts-check - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -const path = require("path"); - -//////////////////////////////////////// - -const noDatabaseDbHandler = require("./utils/noDatabaseDbHandler"); -const varDatabaseDbHandler = require("./utils/varDatabaseDbHandler"); -const createTable = require("./utils/createTable"); -const updateTable = require("./utils/updateTable"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * Create database from Schema - * ============================================================================== - * @description Create database from Schema. This function is called when the user - * runs the "dsql create" command. `NOTE`: there must be a "dsql.schema.json" file - * in the root of the project for this function to work - * - * @param {import("../../types/database-schema.td").DSQL_DatabaseSchemaType[]} dbSchema - An array of database schema objects - */ -async function createDbFromSchema(dbSchema) { - try { - /** - * Grab Schema - * - * @description Grab Schema - */ - - if (!dbSchema || !Array.isArray(dbSchema) || !dbSchema[0]) { - return; - } - - for (let i = 0; i < dbSchema.length; i++) { - /** @type {import("../../types/database-schema.td").DSQL_DatabaseSchemaType} */ - const database = dbSchema[i]; - const { dbFullName, tables } = database; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** @type {{ dbFullName: string }[] | null} */ - const dbCheck = await noDatabaseDbHandler({ query: `SELECT SCHEMA_NAME AS dbFullName FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '${dbFullName}'` }); - - if (dbCheck && dbCheck[0]?.dbFullName) { - // Database Exists - } else { - const newDatabase = await noDatabaseDbHandler({ query: `CREATE DATABASE IF NOT EXISTS \`${dbFullName}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_bin` }); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Select all tables - * @type {{ TABLE_NAME: string }[] | null} - * @description Select All tables in target database - */ - const allTables = await noDatabaseDbHandler({ query: `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='${dbFullName}'` }); - - let tableDropped; - - if (!allTables) { - console.log("No Tables to Update"); - continue; - } - - for (let tb = 0; tb < allTables.length; tb++) { - const { TABLE_NAME } = allTables[tb]; - - /** - * @description Check if TABLE_NAME is part of the tables contained - * in the user schema JSON. If it's not, the table is either deleted - * or the table name has been recently changed - */ - if (!tables.filter((_table) => _table.tableName === TABLE_NAME)[0]) { - const oldTableFilteredArray = tables.filter((_table) => _table.tableNameOld && _table.tableNameOld === TABLE_NAME); - - /** - * @description Check if this table has been recently renamed. Rename - * table id true. Drop table if false - */ - if (oldTableFilteredArray && oldTableFilteredArray[0]) { - console.log("Renaming Table"); - await varDatabaseDbHandler({ - queryString: `RENAME TABLE \`${oldTableFilteredArray[0].tableNameOld}\` TO \`${oldTableFilteredArray[0].tableName}\``, - database: dbFullName, - }); - } else { - console.log(`Dropping Table from ${dbFullName}`); - // deepcode ignore reDOS: - await varDatabaseDbHandler({ - queryString: `DROP TABLE \`${TABLE_NAME}\``, - database: dbFullName, - }); - - tableDropped = true; - } - } - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * @description Iterate through each table and perform table actions - */ - for (let t = 0; t < tables.length; t++) { - const table = tables[t]; - - if (tableDropped) continue; - - const { tableName, fields, indexes } = table; - - /** - * @description Check if table exists - */ - const tableCheck = await varDatabaseDbHandler({ - queryString: ` - SELECT EXISTS ( - SELECT - TABLE_NAME - FROM - information_schema.TABLES - WHERE - TABLE_SCHEMA = ? AND - TABLE_NAME = ? - ) AS tableExists`, - queryValuesArray: [dbFullName, table.tableName], - database: dbFullName, - }); - - //////////////////////////////////////// - - if (tableCheck && tableCheck[0]?.tableExists > 0) { - /** - * @description Update table if table exists - */ - const updateExistingTable = await updateTable({ - dbFullName: dbFullName, - tableName: tableName, - tableInfoArray: fields, - dbSchema, - tableIndexes: indexes, - tableIndex: t, - }); - - if (table.childrenTables && table.childrenTables[0]) { - for (let ch = 0; ch < table.childrenTables.length; ch++) { - const childTable = table.childrenTables[ch]; - - const updateExistingChildTable = await updateTable({ - dbFullName: childTable.dbNameFull, - tableName: childTable.tableName, - tableInfoArray: fields, - dbSchema, - tableIndexes: indexes, - clone: true, - }); - - // console.log(updateExistingChildTable); - } - } - - //////////////////////////////////////// - } else { - //////////////////////////////////////// - - /** - * @description Create new Table if table doesnt exist - */ - const createNewTable = await createTable({ - tableName: tableName, - tableInfoArray: fields, - varDatabaseDbHandler, - dbFullName: dbFullName, - dbSchema, - }); - - if (indexes && indexes[0]) { - /** - * Handle DATASQUIREL Table Indexes - * =================================================== - * @description Iterate through each datasquirel schema - * table index(if available), and perform operations - */ - if (indexes && indexes[0]) { - for (let g = 0; g < indexes.length; g++) { - const { indexType, indexName, indexTableFields, alias } = indexes[g]; - - if (!alias?.match(/./)) continue; - - /** - * @type {any[] | null} - * @description All indexes from MYSQL db - */ - const allExistingIndexes = await varDatabaseDbHandler({ - queryString: `SHOW INDEXES FROM \`${tableName}\``, - database: dbFullName, - }); - - /** - * @description Check for existing Index in MYSQL db - */ - try { - const existingKeyInDb = allExistingIndexes ? allExistingIndexes.filter((indexObject) => indexObject.Key_name === alias) : null; - if (!existingKeyInDb?.[0]) throw new Error("This Index Does not Exist"); - } catch (error) { - /** - * @description Create new index if determined that it - * doesn't exist in MYSQL db - */ - await varDatabaseDbHandler({ - queryString: `CREATE${indexType.match(/fullText/i) ? " FULLTEXT" : ""} INDEX \`${alias}\` ON ${tableName}(${indexTableFields - .map((nm) => nm.value) - .map((nm) => `\`${nm}\``) - .join(",")}) COMMENT 'schema_index'`, - database: dbFullName, - }); - } - } - } - } - } - - //////////////////////////////////////// - } - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("Error in createDbFromSchema => ", error.message); - } -} - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -module.exports = createDbFromSchema; +// @ts-check + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +const path = require("path"); + +//////////////////////////////////////// + +const noDatabaseDbHandler = require("./utils/noDatabaseDbHandler"); +const varDatabaseDbHandler = require("./utils/varDatabaseDbHandler"); +const createTable = require("./utils/createTable"); +const updateTable = require("./utils/updateTable"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Create database from Schema + * ============================================================================== + * @description Create database from Schema. This function is called when the user + * runs the "dsql create" command. `NOTE`: there must be a "dsql.schema.json" file + * in the root of the project for this function to work + * + * @param {import("../../types/database-schema.td").DSQL_DatabaseSchemaType[]} dbSchema - An array of database schema objects + */ +async function createDbFromSchema(dbSchema) { + try { + /** + * Grab Schema + * + * @description Grab Schema + */ + + if (!dbSchema || !Array.isArray(dbSchema) || !dbSchema[0]) { + return; + } + + for (let i = 0; i < dbSchema.length; i++) { + /** @type {import("../../types/database-schema.td").DSQL_DatabaseSchemaType} */ + const database = dbSchema[i]; + const { dbFullName, tables } = database; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** @type {{ dbFullName: string }[] | null} */ + const dbCheck = await noDatabaseDbHandler({ query: `SELECT SCHEMA_NAME AS dbFullName FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '${dbFullName}'` }); + + if (dbCheck && dbCheck[0]?.dbFullName) { + // Database Exists + } else { + const newDatabase = await noDatabaseDbHandler({ query: `CREATE DATABASE IF NOT EXISTS \`${dbFullName}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_bin` }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Select all tables + * @type {{ TABLE_NAME: string }[] | null} + * @description Select All tables in target database + */ + const allTables = await noDatabaseDbHandler({ query: `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='${dbFullName}'` }); + + let tableDropped; + + if (!allTables) { + console.log("No Tables to Update"); + continue; + } + + for (let tb = 0; tb < allTables.length; tb++) { + const { TABLE_NAME } = allTables[tb]; + + /** + * @description Check if TABLE_NAME is part of the tables contained + * in the user schema JSON. If it's not, the table is either deleted + * or the table name has been recently changed + */ + if (!tables.filter((_table) => _table.tableName === TABLE_NAME)[0]) { + const oldTableFilteredArray = tables.filter((_table) => _table.tableNameOld && _table.tableNameOld === TABLE_NAME); + + /** + * @description Check if this table has been recently renamed. Rename + * table id true. Drop table if false + */ + if (oldTableFilteredArray && oldTableFilteredArray[0]) { + console.log("Renaming Table"); + await varDatabaseDbHandler({ + queryString: `RENAME TABLE \`${oldTableFilteredArray[0].tableNameOld}\` TO \`${oldTableFilteredArray[0].tableName}\``, + database: dbFullName, + }); + } else { + console.log(`Dropping Table from ${dbFullName}`); + // deepcode ignore reDOS: + await varDatabaseDbHandler({ + queryString: `DROP TABLE \`${TABLE_NAME}\``, + database: dbFullName, + }); + + tableDropped = true; + } + } + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * @description Iterate through each table and perform table actions + */ + for (let t = 0; t < tables.length; t++) { + const table = tables[t]; + + if (tableDropped) continue; + + const { tableName, fields, indexes } = table; + + /** + * @description Check if table exists + */ + const tableCheck = await varDatabaseDbHandler({ + queryString: ` + SELECT EXISTS ( + SELECT + TABLE_NAME + FROM + information_schema.TABLES + WHERE + TABLE_SCHEMA = ? AND + TABLE_NAME = ? + ) AS tableExists`, + queryValuesArray: [dbFullName, table.tableName], + database: dbFullName, + }); + + //////////////////////////////////////// + + if (tableCheck && tableCheck[0]?.tableExists > 0) { + /** + * @description Update table if table exists + */ + const updateExistingTable = await updateTable({ + dbFullName: dbFullName, + tableName: tableName, + tableInfoArray: fields, + dbSchema, + tableIndexes: indexes, + tableIndex: t, + }); + + if (table.childrenTables && table.childrenTables[0]) { + for (let ch = 0; ch < table.childrenTables.length; ch++) { + const childTable = table.childrenTables[ch]; + + const updateExistingChildTable = await updateTable({ + dbFullName: childTable.dbNameFull, + tableName: childTable.tableName, + tableInfoArray: fields, + dbSchema, + tableIndexes: indexes, + clone: true, + }); + + // console.log(updateExistingChildTable); + } + } + + //////////////////////////////////////// + } else { + //////////////////////////////////////// + + /** + * @description Create new Table if table doesnt exist + */ + const createNewTable = await createTable({ + tableName: tableName, + tableInfoArray: fields, + varDatabaseDbHandler, + dbFullName: dbFullName, + dbSchema, + }); + + if (indexes && indexes[0]) { + /** + * Handle DATASQUIREL Table Indexes + * =================================================== + * @description Iterate through each datasquirel schema + * table index(if available), and perform operations + */ + if (indexes && indexes[0]) { + for (let g = 0; g < indexes.length; g++) { + const { indexType, indexName, indexTableFields, alias } = indexes[g]; + + if (!alias?.match(/./)) continue; + + /** + * @type {any[] | null} + * @description All indexes from MYSQL db + */ + const allExistingIndexes = await varDatabaseDbHandler({ + queryString: `SHOW INDEXES FROM \`${tableName}\``, + database: dbFullName, + }); + + /** + * @description Check for existing Index in MYSQL db + */ + try { + const existingKeyInDb = allExistingIndexes ? allExistingIndexes.filter((indexObject) => indexObject.Key_name === alias) : null; + if (!existingKeyInDb?.[0]) throw new Error("This Index Does not Exist"); + } catch (error) { + /** + * @description Create new index if determined that it + * doesn't exist in MYSQL db + */ + await varDatabaseDbHandler({ + queryString: `CREATE${indexType.match(/fullText/i) ? " FULLTEXT" : ""} INDEX \`${alias}\` ON ${tableName}(${indexTableFields + .map((nm) => nm.value) + .map((nm) => `\`${nm}\``) + .join(",")}) COMMENT 'schema_index'`, + database: dbFullName, + }); + } + } + } + } + } + + //////////////////////////////////////// + } + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } catch (/** @type {*} */ error) { + console.log("Error in createDbFromSchema => ", error.message); + } +} + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +module.exports = createDbFromSchema; diff --git a/engine/engine/data/dataTypes.json b/engine/engine/data/dataTypes.json index bd42ec3..daf282a 100644 --- a/engine/engine/data/dataTypes.json +++ b/engine/engine/data/dataTypes.json @@ -1,73 +1,73 @@ -[ - { - "title": "VARCHAR", - "name": "VARCHAR", - "value": "0-255", - "argument": true, - "description": "Varchar is simply letters and numbers within the range 0 - 255", - "maxValue": 255 - }, - { - "title": "TINYINT", - "name": "TINYINT", - "value": "0-100", - "description": "TINYINT means Integers: 0 to 100", - "maxValue": 127 - }, - { - "title": "SMALLINT", - "name": "SMALLINT", - "value": "0-255", - "description": "SMALLINT means Integers: 0 to 240933", - "maxValue": 32767 - }, - { - "title": "MEDIUMINT", - "name": "MEDIUMINT", - "value": "0-255", - "description": "MEDIUMINT means Integers: 0 to 1245568545560", - "maxValue": 8388607 - }, - { - "title": "INT", - "name": "INT", - "value": "0-255", - "description": "INT means Integers: 0 to 12560", - "maxValue": 2147483647 - }, - { - "title": "BIGINT", - "name": "BIGINT", - "value": "0-255", - "description": "BIGINT means Integers: 0 to 1245569056767568545560", - "maxValue": 2e63 - }, - { - "title": "TINYTEXT", - "name": "TINYTEXT", - "value": "0-255", - "description": "Text with 255 max characters", - "maxValue": 127 - }, - { - "title": "TEXT", - "name": "TEXT", - "value": "0-100", - "description": "MEDIUMTEXT is just text with max length 16,777,215", - "maxValue": 127 - }, - { - "title": "MEDIUMTEXT", - "name": "MEDIUMTEXT", - "value": "0-255", - "description": "MEDIUMTEXT is just text with max length 16,777,215", - "maxValue": 127 - }, - { - "title": "LONGTEXT", - "name": "LONGTEXT", - "value": "0-255", - "description": "LONGTEXT is just text with max length 4,294,967,295", - "maxValue": 127 - } -] +[ + { + "title": "VARCHAR", + "name": "VARCHAR", + "value": "0-255", + "argument": true, + "description": "Varchar is simply letters and numbers within the range 0 - 255", + "maxValue": 255 + }, + { + "title": "TINYINT", + "name": "TINYINT", + "value": "0-100", + "description": "TINYINT means Integers: 0 to 100", + "maxValue": 127 + }, + { + "title": "SMALLINT", + "name": "SMALLINT", + "value": "0-255", + "description": "SMALLINT means Integers: 0 to 240933", + "maxValue": 32767 + }, + { + "title": "MEDIUMINT", + "name": "MEDIUMINT", + "value": "0-255", + "description": "MEDIUMINT means Integers: 0 to 1245568545560", + "maxValue": 8388607 + }, + { + "title": "INT", + "name": "INT", + "value": "0-255", + "description": "INT means Integers: 0 to 12560", + "maxValue": 2147483647 + }, + { + "title": "BIGINT", + "name": "BIGINT", + "value": "0-255", + "description": "BIGINT means Integers: 0 to 1245569056767568545560", + "maxValue": 2e63 + }, + { + "title": "TINYTEXT", + "name": "TINYTEXT", + "value": "0-255", + "description": "Text with 255 max characters", + "maxValue": 127 + }, + { + "title": "TEXT", + "name": "TEXT", + "value": "0-100", + "description": "MEDIUMTEXT is just text with max length 16,777,215", + "maxValue": 127 + }, + { + "title": "MEDIUMTEXT", + "name": "MEDIUMTEXT", + "value": "0-255", + "description": "MEDIUMTEXT is just text with max length 16,777,215", + "maxValue": 127 + }, + { + "title": "LONGTEXT", + "name": "LONGTEXT", + "value": "0-255", + "description": "LONGTEXT is just text with max length 4,294,967,295", + "maxValue": 127 + } +] diff --git a/engine/engine/data/defaultFields.json b/engine/engine/data/defaultFields.json index 56bb62e..aaaa742 100644 --- a/engine/engine/data/defaultFields.json +++ b/engine/engine/data/defaultFields.json @@ -1,39 +1,39 @@ -[ - { - "fieldName": "id", - "dataType": "BIGINT", - "notNullValue": true, - "primaryKey": true, - "autoIncrement": true - }, - { - "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" - } -] +[ + { + "fieldName": "id", + "dataType": "BIGINT", + "notNullValue": true, + "primaryKey": true, + "autoIncrement": true + }, + { + "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/data/possibleFields.json b/engine/engine/data/possibleFields.json index 33a0805..9ba10d1 100644 --- a/engine/engine/data/possibleFields.json +++ b/engine/engine/data/possibleFields.json @@ -1,17 +1,17 @@ -{ - "fieldName": "string", - "dataType": "BIGINT", - "nullValue": true, - "primaryKey": true, - "autoIncrement": true, - "defaultValue": "CURRENT_TIMESTAMP", - "defaultValueLiteral": "CURRENT_TIMESTAMP", - "notNullValue": true, - "foreignKey": { - "foreignKeyName": "Name", - "destinationTableName": "Table Name", - "destinationTableColumnName": "Column Name", - "cascadeDelete": true, - "cascadeUpdate": true - } -} +{ + "fieldName": "string", + "dataType": "BIGINT", + "nullValue": true, + "primaryKey": true, + "autoIncrement": true, + "defaultValue": "CURRENT_TIMESTAMP", + "defaultValueLiteral": "CURRENT_TIMESTAMP", + "notNullValue": true, + "foreignKey": { + "foreignKeyName": "Name", + "destinationTableName": "Table Name", + "destinationTableColumnName": "Column Name", + "cascadeDelete": true, + "cascadeUpdate": true + } +} diff --git a/engine/engine/data/presets/users.json b/engine/engine/data/presets/users.json index 2533033..843b473 100644 --- a/engine/engine/data/presets/users.json +++ b/engine/engine/data/presets/users.json @@ -1,132 +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" - } - ] -} +{ + "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/utils/camelJoinedtoCamelSpace.js b/engine/engine/utils/camelJoinedtoCamelSpace.js index 7435818..ff136bf 100644 --- a/engine/engine/utils/camelJoinedtoCamelSpace.js +++ b/engine/engine/utils/camelJoinedtoCamelSpace.js @@ -1,54 +1,54 @@ -// @ts-check - -/** - * Convert Camel Joined Text to Camel Spaced Text - * ============================================================================== - * @description this function takes a camel cased text without spaces, and returns - * a camel-case-spaced text - * - * @param {string} text - text string without spaces - * - * @returns {string | null} - */ -function camelJoinedtoCamelSpace(text) { - if (!text?.match(/./)) { - return ""; - } - - if (text?.match(/ /)) { - return text; - } - - if (text) { - let textArray = text.split(""); - - let capIndexes = []; - - for (let i = 0; i < textArray.length; i++) { - const char = textArray[i]; - - if (i === 0) continue; - if (char.match(/[A-Z]/)) { - capIndexes.push(i); - } - } - - let textChunks = [`${textArray[0].toUpperCase()}${text.substring(1, capIndexes[0])}`]; - - for (let j = 0; j < capIndexes.length; j++) { - const capIndex = capIndexes[j]; - if (capIndex === 0) continue; - - const startIndex = capIndex + 1; - const endIndex = capIndexes[j + 1]; - - textChunks.push(`${textArray[capIndex].toUpperCase()}${text.substring(startIndex, endIndex)}`); - } - - return textChunks.join(" "); - } else { - return null; - } -} - -module.exports = camelJoinedtoCamelSpace; +// @ts-check + +/** + * Convert Camel Joined Text to Camel Spaced Text + * ============================================================================== + * @description this function takes a camel cased text without spaces, and returns + * a camel-case-spaced text + * + * @param {string} text - text string without spaces + * + * @returns {string | null} + */ +function camelJoinedtoCamelSpace(text) { + if (!text?.match(/./)) { + return ""; + } + + if (text?.match(/ /)) { + return text; + } + + if (text) { + let textArray = text.split(""); + + let capIndexes = []; + + for (let i = 0; i < textArray.length; i++) { + const char = textArray[i]; + + if (i === 0) continue; + if (char.match(/[A-Z]/)) { + capIndexes.push(i); + } + } + + let textChunks = [`${textArray[0].toUpperCase()}${text.substring(1, capIndexes[0])}`]; + + for (let j = 0; j < capIndexes.length; j++) { + const capIndex = capIndexes[j]; + if (capIndex === 0) continue; + + const startIndex = capIndex + 1; + const endIndex = capIndexes[j + 1]; + + textChunks.push(`${textArray[capIndex].toUpperCase()}${text.substring(startIndex, endIndex)}`); + } + + return textChunks.join(" "); + } else { + return null; + } +} + +module.exports = camelJoinedtoCamelSpace; diff --git a/engine/engine/utils/createTable.js b/engine/engine/utils/createTable.js index 01792ab..b7d3cfd 100644 --- a/engine/engine/utils/createTable.js +++ b/engine/engine/utils/createTable.js @@ -1,112 +1,112 @@ -// @ts-check - -const generateColumnDescription = require("./generateColumnDescription"); -const supplementTable = require("./supplementTable"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -module.exports = async function createTable({ dbFullName, tableName, tableInfoArray, varDatabaseDbHandler, dbSchema }) { - /** - * Format tableInfoArray - * - * @description Format tableInfoArray - */ - const finalTable = supplementTable({ tableInfoArray: tableInfoArray }); - - /** - * Grab Schema - * - * @description Grab Schema - */ - const createTableQueryArray = []; - - createTableQueryArray.push(`CREATE TABLE IF NOT EXISTS \`${tableName}\` (`); - - //////////////////////////////////////// - - let primaryKeySet = false; - let foreignKeys = []; - - //////////////////////////////////////// - - for (let i = 0; i < finalTable.length; i++) { - const column = finalTable[i]; - const { fieldName, dataType, nullValue, primaryKey, autoIncrement, defaultValue, defaultValueLiteral, foreignKey, updatedField } = column; - - if (foreignKey) { - foreignKeys.push({ - fieldName: fieldName, - ...foreignKey, - }); - } - - let { fieldEntryText, newPrimaryKeySet } = generateColumnDescription({ columnData: column, primaryKeySet: primaryKeySet }); - - primaryKeySet = newPrimaryKeySet; - - //////////////////////////////////////// - - if (fieldName?.match(/updated_timestamp/i)) { - fieldEntryText += " ON UPDATE CURRENT_TIMESTAMP"; - } - - //////////////////////////////////////// - - const comma = (() => { - if (foreignKeys[0]) return ","; - if (i === finalTable.length - 1) return ""; - return ","; - })(); - - createTableQueryArray.push(" " + fieldEntryText + comma); - - //////////////////////////////////////// - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - if (foreignKeys[0]) { - foreignKeys.forEach((foreighKey, index, array) => { - const { fieldName, destinationTableName, destinationTableColumnName, cascadeDelete, cascadeUpdate, foreignKeyName } = foreighKey; - - const comma = (() => { - if (index === foreignKeys.length - 1) return ""; - return ","; - })(); - - createTableQueryArray.push(` CONSTRAINT \`${foreignKeyName}\` FOREIGN KEY (\`${fieldName}\`) REFERENCES \`${destinationTableName}\`(${destinationTableColumnName})${cascadeDelete ? " ON DELETE CASCADE" : ""}${cascadeUpdate ? " ON UPDATE CASCADE" : ""}${comma}`); - }); - } - - //////////////////////////////////////// - - createTableQueryArray.push(`) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;`); - - const createTableQuery = createTableQueryArray.join("\n"); - - //////////////////////////////////////// - - const newTable = await varDatabaseDbHandler({ - queryString: createTableQuery, - database: dbFullName, - }); - - return newTable; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// -}; - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ +// @ts-check + +const generateColumnDescription = require("./generateColumnDescription"); +const supplementTable = require("./supplementTable"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +module.exports = async function createTable({ dbFullName, tableName, tableInfoArray, varDatabaseDbHandler, dbSchema }) { + /** + * Format tableInfoArray + * + * @description Format tableInfoArray + */ + const finalTable = supplementTable({ tableInfoArray: tableInfoArray }); + + /** + * Grab Schema + * + * @description Grab Schema + */ + const createTableQueryArray = []; + + createTableQueryArray.push(`CREATE TABLE IF NOT EXISTS \`${tableName}\` (`); + + //////////////////////////////////////// + + let primaryKeySet = false; + let foreignKeys = []; + + //////////////////////////////////////// + + for (let i = 0; i < finalTable.length; i++) { + const column = finalTable[i]; + const { fieldName, dataType, nullValue, primaryKey, autoIncrement, defaultValue, defaultValueLiteral, foreignKey, updatedField } = column; + + if (foreignKey) { + foreignKeys.push({ + fieldName: fieldName, + ...foreignKey, + }); + } + + let { fieldEntryText, newPrimaryKeySet } = generateColumnDescription({ columnData: column, primaryKeySet: primaryKeySet }); + + primaryKeySet = newPrimaryKeySet; + + //////////////////////////////////////// + + if (fieldName?.match(/updated_timestamp/i)) { + fieldEntryText += " ON UPDATE CURRENT_TIMESTAMP"; + } + + //////////////////////////////////////// + + const comma = (() => { + if (foreignKeys[0]) return ","; + if (i === finalTable.length - 1) return ""; + return ","; + })(); + + createTableQueryArray.push(" " + fieldEntryText + comma); + + //////////////////////////////////////// + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + if (foreignKeys[0]) { + foreignKeys.forEach((foreighKey, index, array) => { + const { fieldName, destinationTableName, destinationTableColumnName, cascadeDelete, cascadeUpdate, foreignKeyName } = foreighKey; + + const comma = (() => { + if (index === foreignKeys.length - 1) return ""; + return ","; + })(); + + createTableQueryArray.push(` CONSTRAINT \`${foreignKeyName}\` FOREIGN KEY (\`${fieldName}\`) REFERENCES \`${destinationTableName}\`(${destinationTableColumnName})${cascadeDelete ? " ON DELETE CASCADE" : ""}${cascadeUpdate ? " ON UPDATE CASCADE" : ""}${comma}`); + }); + } + + //////////////////////////////////////// + + createTableQueryArray.push(`) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;`); + + const createTableQuery = createTableQueryArray.join("\n"); + + //////////////////////////////////////// + + const newTable = await varDatabaseDbHandler({ + queryString: createTableQuery, + database: dbFullName, + }); + + return newTable; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// +}; + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ diff --git a/engine/engine/utils/dbHandler.js b/engine/engine/utils/dbHandler.js index 46fbdb2..4d4009f 100644 --- a/engine/engine/utils/dbHandler.js +++ b/engine/engine/utils/dbHandler.js @@ -1,157 +1,173 @@ -/** # MODULE TRACE -====================================================================== - * Detected 8 files that call this module. The files are listed below: -====================================================================== - * `require` Statement Found in [noDatabaseDbHandler.js](d:\GitHub\dsql\engine\engine\utils\noDatabaseDbHandler.js) - * `require` Statement Found in [varDatabaseDbHandler.js](d:\GitHub\dsql\engine\engine\utils\varDatabaseDbHandler.js) - * `require` Statement Found in [addDbEntry.js](d:\GitHub\dsql\engine\query\utils\addDbEntry.js) - * `require` Statement Found in [deleteDbEntry.js](d:\GitHub\dsql\engine\query\utils\deleteDbEntry.js) - * `require` Statement Found in [runQuery.js](d:\GitHub\dsql\engine\query\utils\runQuery.js) - * `require` Statement Found in [updateDbEntry.js](d:\GitHub\dsql\engine\query\utils\updateDbEntry.js) - * `require` Statement Found in [githubLogin.js](d:\GitHub\dsql\engine\user\social\utils\githubLogin.js) - * `require` Statement Found in [googleLogin.js](d:\GitHub\dsql\engine\user\social\utils\googleLogin.js) -==== MODULE TRACE END ==== */ - -// @ts-check - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -const fs = require("fs"); -const mysql = require("mysql"); -const parseDbResults = require("./parseDbResults"); - -const connection = mysql.createConnection({ - host: process.env.DSQL_HOST, - user: process.env.DSQL_USER, - database: process.env.DSQL_DB_NAME, - password: process.env.DSQL_PASS, - charset: "utf8mb4", - port: process.env.DSQL_PORT?.match(/.../) ? parseInt(process.env.DSQL_PORT) : undefined, - timeout: 5000, -}); - -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// - -/** - * Main DB Handler Function - * ============================================================================== - * @async - * @param {object} params - Single Param object containing params - * @param {string} params.query - Query String - * @param {(string | number)[]} [params.values] - Values - * @param {import("../../../types/database-schema.td").DSQL_DatabaseSchemaType} [params.dbSchema] - Database Schema - * @param {string} [params.database] - Target Database - * @param {string} [params.tableName] - Target Table Name - * - * @returns {Promise<*>} - */ -module.exports = async function dbHandler({ query, values, database, dbSchema, tableName }) { - /** - * Declare variables - * - * @description Declare "results" variable - */ - let changeDbError; - - if (database) { - connection.changeUser({ database: database }, (error) => { - if (error) { - console.log("DB handler error in switching database:", error.message); - changeDbError = error.message; - } - }); - } - - if (changeDbError) { - return { error: changeDbError }; - } - - /** - * Declare variables - * - * @description Declare "results" variable - */ - let results; - - /** - * Fetch from db - * - * @description Fetch data from db if no cache - */ - try { - results = await new Promise((resolve, reject) => { - if (values?.[0]) { - connection.query(query, values, (error, results, fields) => { - if (error) { - console.log("DB handler error with values array:", error.message); - console.log("SQL:", error.sql); - console.log("State:", error.sqlState, error.sqlMessage); - - resolve({ - error: error.message, - }); - } else { - resolve(JSON.parse(JSON.stringify(results))); - } - - // setTimeout(() => { - // endConnection(connection); - // }, 500); - }); - } else { - connection.query(query, (error, results, fields) => { - if (error) { - console.log("DB handler error:", error.message); - console.log("SQL:", error.sql); - console.log("State:", error.sqlState, error.sqlMessage); - - resolve({ - error: error.message, - }); - } else { - resolve(JSON.parse(JSON.stringify(results))); - } - // setTimeout(() => { - // endConnection(connection); - // }, 500); - }); - } - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("DB handler error:", error.message); - - results = null; - } - - /** - * Return results - * - * @description Return results add to cache if "req" param is passed - */ - // if (results && dbSchema && tableName) { - // const tableSchema = dbSchema.tables.find((table) => table.tableName === tableName); - // const parsedResults = parseDbResults({ - // unparsedResults: results, - // tableSchema: tableSchema, - // }); - - // return parsedResults; - // } else - if (results) { - return results; - } else { - console.log("DSQL DB handler no results received for Query =>", query); - return null; - } -}; +/** # MODULE TRACE +====================================================================== + * Detected 8 files that call this module. The files are listed below: +====================================================================== + * `require` Statement Found in [noDatabaseDbHandler.js](d:\GitHub\dsql\engine\engine\utils\noDatabaseDbHandler.js) + * `require` Statement Found in [varDatabaseDbHandler.js](d:\GitHub\dsql\engine\engine\utils\varDatabaseDbHandler.js) + * `require` Statement Found in [addDbEntry.js](d:\GitHub\dsql\engine\query\utils\addDbEntry.js) + * `require` Statement Found in [deleteDbEntry.js](d:\GitHub\dsql\engine\query\utils\deleteDbEntry.js) + * `require` Statement Found in [runQuery.js](d:\GitHub\dsql\engine\query\utils\runQuery.js) + * `require` Statement Found in [updateDbEntry.js](d:\GitHub\dsql\engine\query\utils\updateDbEntry.js) + * `require` Statement Found in [githubLogin.js](d:\GitHub\dsql\engine\user\social\utils\githubLogin.js) + * `require` Statement Found in [googleLogin.js](d:\GitHub\dsql\engine\user\social\utils\googleLogin.js) +==== MODULE TRACE END ==== */ + +// @ts-check + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +const fs = require("fs"); +const mysql = require("mysql"); +const parseDbResults = require("./parseDbResults"); + +const connection = mysql.createConnection({ + host: process.env.DSQL_HOST, + user: process.env.DSQL_USER, + database: process.env.DSQL_DB_NAME, + password: process.env.DSQL_PASS, + charset: "utf8mb4", + port: process.env.DSQL_PORT?.match(/.../) + ? parseInt(process.env.DSQL_PORT) + : undefined, + timeout: 5000, +}); + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +/** + * Main DB Handler Function + * ============================================================================== + * @async + * @param {object} params - Single Param object containing params + * @param {string} params.query - Query String + * @param {(string | number)[]} [params.values] - Values + * @param {import("../../../types/database-schema.td").DSQL_DatabaseSchemaType} [params.dbSchema] - Database Schema + * @param {string} [params.database] - Target Database + * @param {string} [params.tableName] - Target Table Name + * + * @returns {Promise<*>} + */ +module.exports = async function dbHandler({ + query, + values, + database, + dbSchema, + tableName, +}) { + /** + * Declare variables + * + * @description Declare "results" variable + */ + let changeDbError; + + console.log(connection.config); + + if (database) { + connection.changeUser({ database: database }, (error) => { + if (error) { + console.log( + "DB handler error in switching database:", + error.message + ); + changeDbError = error.message; + } + }); + } + + if (changeDbError) { + return { error: changeDbError }; + } + + /** + * Declare variables + * + * @description Declare "results" variable + */ + let results; + + /** + * Fetch from db + * + * @description Fetch data from db if no cache + */ + try { + results = await new Promise((resolve, reject) => { + if (values?.[0]) { + connection.query(query, values, (error, results, fields) => { + if (error) { + console.log( + "DB handler error with values array:", + error.message + ); + console.log("SQL:", error.sql); + console.log("State:", error.sqlState, error.sqlMessage); + + resolve({ + error: error.message, + }); + } else { + resolve(JSON.parse(JSON.stringify(results))); + } + + // setTimeout(() => { + // endConnection(connection); + // }, 500); + }); + } else { + connection.query(query, (error, results, fields) => { + if (error) { + console.log("DB handler error:", error.message); + console.log("SQL:", error.sql); + console.log("State:", error.sqlState, error.sqlMessage); + + resolve({ + error: error.message, + }); + } else { + resolve(JSON.parse(JSON.stringify(results))); + } + // setTimeout(() => { + // endConnection(connection); + // }, 500); + }); + } + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } catch (/** @type {*} */ error) { + console.log("DB handler error:", error.message); + + results = null; + } + + /** + * Return results + * + * @description Return results add to cache if "req" param is passed + */ + // if (results && dbSchema && tableName) { + // const tableSchema = dbSchema.tables.find((table) => table.tableName === tableName); + // const parsedResults = parseDbResults({ + // unparsedResults: results, + // tableSchema: tableSchema, + // }); + + // return parsedResults; + // } else + if (results) { + return results; + } else { + console.log("DSQL DB handler no results received for Query =>", query); + return null; + } +}; diff --git a/engine/engine/utils/defaultFieldsRegexp.js b/engine/engine/utils/defaultFieldsRegexp.js index f27e1bd..0e6f212 100644 --- a/engine/engine/utils/defaultFieldsRegexp.js +++ b/engine/engine/utils/defaultFieldsRegexp.js @@ -1,13 +1,13 @@ -/** - * Regular expression to match default fields - * - * @description Regular expression to match default fields - * @type {RegExp} - */ -const defaultFieldsRegexp = /^id$|^date_created$|^date_created_code$|^date_created_timestamp$|^date_updated$|^date_updated_code$|^date_updated_timestamp$/; - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -module.exports = defaultFieldsRegexp; +/** + * Regular expression to match default fields + * + * @description Regular expression to match default fields + * @type {RegExp} + */ +const defaultFieldsRegexp = /^id$|^date_created$|^date_created_code$|^date_created_timestamp$|^date_updated$|^date_updated_code$|^date_updated_timestamp$/; + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +module.exports = defaultFieldsRegexp; diff --git a/engine/engine/utils/endConnection.js b/engine/engine/utils/endConnection.js index 128539c..c0fc177 100644 --- a/engine/engine/utils/endConnection.js +++ b/engine/engine/utils/endConnection.js @@ -1,16 +1,16 @@ -// @ts-check - -const mysql = require("mysql"); - -/** - * @param {mysql.Connection} connection - the active MYSQL connection - */ -function endConnection(connection) { - if (connection.state !== "disconnected") { - connection.end((err) => { - console.log(err?.message); - }); - } -} - -module.exports = endConnection; +// @ts-check + +const mysql = require("mysql"); + +/** + * @param {mysql.Connection} connection - the active MYSQL connection + */ +function endConnection(connection) { + if (connection.state !== "disconnected") { + connection.end((err) => { + console.log(err?.message); + }); + } +} + +module.exports = endConnection; diff --git a/engine/engine/utils/generateColumnDescription.js b/engine/engine/utils/generateColumnDescription.js index 2408ad2..99a7054 100644 --- a/engine/engine/utils/generateColumnDescription.js +++ b/engine/engine/utils/generateColumnDescription.js @@ -1,68 +1,68 @@ -// @ts-check - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * Generate SQL text for Field - * ============================================================================== - * @param {object} params - Single object params - * @param {import("../../../types/database-schema.td").DSQL_FieldSchemaType} params.columnData - Field object - * @param {boolean} [params.primaryKeySet] - Table Name(slug) - * - * @returns {{fieldEntryText: string, newPrimaryKeySet: boolean}} - */ -module.exports = function generateColumnDescription({ columnData, primaryKeySet }) { - /** - * Format tableInfoArray - * - * @description Format tableInfoArray - */ - const { fieldName, dataType, nullValue, primaryKey, autoIncrement, defaultValue, defaultValueLiteral, notNullValue } = columnData; - - let fieldEntryText = ""; - - fieldEntryText += `\`${fieldName}\` ${dataType}`; - - //////////////////////////////////////// - - if (nullValue) { - fieldEntryText += " DEFAULT NULL"; - } else if (defaultValueLiteral) { - fieldEntryText += ` DEFAULT ${defaultValueLiteral}`; - } else if (defaultValue) { - fieldEntryText += ` DEFAULT '${defaultValue}'`; - } else if (notNullValue) { - fieldEntryText += ` NOT NULL`; - } - - //////////////////////////////////////// - - if (primaryKey && !primaryKeySet) { - fieldEntryText += " PRIMARY KEY"; - primaryKeySet = true; - } - - //////////////////////////////////////// - - if (autoIncrement) { - fieldEntryText += " AUTO_INCREMENT"; - primaryKeySet = true; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - return { fieldEntryText, newPrimaryKeySet: primaryKeySet || false }; -}; - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ +// @ts-check + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Generate SQL text for Field + * ============================================================================== + * @param {object} params - Single object params + * @param {import("../../../types/database-schema.td").DSQL_FieldSchemaType} params.columnData - Field object + * @param {boolean} [params.primaryKeySet] - Table Name(slug) + * + * @returns {{fieldEntryText: string, newPrimaryKeySet: boolean}} + */ +module.exports = function generateColumnDescription({ columnData, primaryKeySet }) { + /** + * Format tableInfoArray + * + * @description Format tableInfoArray + */ + const { fieldName, dataType, nullValue, primaryKey, autoIncrement, defaultValue, defaultValueLiteral, notNullValue } = columnData; + + let fieldEntryText = ""; + + fieldEntryText += `\`${fieldName}\` ${dataType}`; + + //////////////////////////////////////// + + if (nullValue) { + fieldEntryText += " DEFAULT NULL"; + } else if (defaultValueLiteral) { + fieldEntryText += ` DEFAULT ${defaultValueLiteral}`; + } else if (defaultValue) { + fieldEntryText += ` DEFAULT '${defaultValue}'`; + } else if (notNullValue) { + fieldEntryText += ` NOT NULL`; + } + + //////////////////////////////////////// + + if (primaryKey && !primaryKeySet) { + fieldEntryText += " PRIMARY KEY"; + primaryKeySet = true; + } + + //////////////////////////////////////// + + if (autoIncrement) { + fieldEntryText += " AUTO_INCREMENT"; + primaryKeySet = true; + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + return { fieldEntryText, newPrimaryKeySet: primaryKeySet || false }; +}; + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ diff --git a/engine/engine/utils/noDatabaseDbHandler.js b/engine/engine/utils/noDatabaseDbHandler.js index 1b747d4..13c7d08 100644 --- a/engine/engine/utils/noDatabaseDbHandler.js +++ b/engine/engine/utils/noDatabaseDbHandler.js @@ -1,89 +1,89 @@ -// @ts-check - -const fs = require("fs"); -const dbHandler = require("./dbHandler"); -const mysql = require("mysql"); -const endConnection = require("./endConnection"); - -const connection = mysql.createConnection({ - host: process.env.DSQL_HOST, - user: process.env.DSQL_USER, - password: process.env.DSQL_PASS, - charset: "utf8mb4", - port: process.env.DSQL_PORT?.match(/.../) ? parseInt(process.env.DSQL_PORT) : undefined, - timeout: 5000, -}); - -/** - * Create database from Schema Function - * ============================================================================== - * @param {object} params - Single Param object containing params - * @param {string} params.query - Query String - * @param {string[]} [params.values] - Values - * - * @returns {Promise} - */ -module.exports = async function noDatabaseDbHandler({ query, values }) { - /** - * Declare variables - * - * @description Declare "results" variable - */ - let results; - - /** - * Fetch from db - * - * @description Fetch data from db if no cache - */ - try { - /** ********************* Run Query */ - results = await new Promise((resolve, reject) => { - if (values) { - connection.query(query, values, (error, results, fields) => { - if (error) { - console.log("NO-DB handler error:", error.message); - resolve({ - error: error.message, - }); - } else { - resolve(JSON.parse(JSON.stringify(results))); - } - // setTimeout(() => { - // endConnection(connection); - // }, 500); - }); - } else { - connection.query(query, (error, results, fields) => { - if (error) { - console.log("NO-DB handler error:", error.message); - resolve({ - error: error.message, - }); - } else { - resolve(JSON.parse(JSON.stringify(results))); - } - // setTimeout(() => { - // endConnection(connection); - // }, 500); - }); - } - }); - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("ERROR in noDatabaseDbHandler =>", error.message); - } - - /** - * Return results - * - * @description Return results add to cache if "req" param is passed - */ - if (results) { - return results; - } else { - return null; - } -}; +// @ts-check + +const fs = require("fs"); +const dbHandler = require("./dbHandler"); +const mysql = require("mysql"); +const endConnection = require("./endConnection"); + +const connection = mysql.createConnection({ + host: process.env.DSQL_HOST, + user: process.env.DSQL_USER, + password: process.env.DSQL_PASS, + charset: "utf8mb4", + port: process.env.DSQL_PORT?.match(/.../) ? parseInt(process.env.DSQL_PORT) : undefined, + timeout: 5000, +}); + +/** + * Create database from Schema Function + * ============================================================================== + * @param {object} params - Single Param object containing params + * @param {string} params.query - Query String + * @param {string[]} [params.values] - Values + * + * @returns {Promise} + */ +module.exports = async function noDatabaseDbHandler({ query, values }) { + /** + * Declare variables + * + * @description Declare "results" variable + */ + let results; + + /** + * Fetch from db + * + * @description Fetch data from db if no cache + */ + try { + /** ********************* Run Query */ + results = await new Promise((resolve, reject) => { + if (values) { + connection.query(query, values, (error, results, fields) => { + if (error) { + console.log("NO-DB handler error:", error.message); + resolve({ + error: error.message, + }); + } else { + resolve(JSON.parse(JSON.stringify(results))); + } + // setTimeout(() => { + // endConnection(connection); + // }, 500); + }); + } else { + connection.query(query, (error, results, fields) => { + if (error) { + console.log("NO-DB handler error:", error.message); + resolve({ + error: error.message, + }); + } else { + resolve(JSON.parse(JSON.stringify(results))); + } + // setTimeout(() => { + // endConnection(connection); + // }, 500); + }); + } + }); + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } catch (/** @type {*} */ error) { + console.log("ERROR in noDatabaseDbHandler =>", error.message); + } + + /** + * Return results + * + * @description Return results add to cache if "req" param is passed + */ + if (results) { + return results; + } else { + return null; + } +}; diff --git a/engine/engine/utils/parseDbResults.js b/engine/engine/utils/parseDbResults.js index e893751..211070c 100644 --- a/engine/engine/utils/parseDbResults.js +++ b/engine/engine/utils/parseDbResults.js @@ -1,76 +1,76 @@ -// @ts-check - -const decrypt = require("../../../functions/decrypt"); -// @ts-ignore -const defaultFieldsRegexp = require("./defaultFieldsRegexp"); - -/** - * Parse Database results - * ============================================================================== - * @description this function takes a database results array gotten from a DB handler - * function, decrypts encrypted fields, and returns an updated array with no encrypted - * fields - * - * @param {object} params - Single object params - * @param {*[]} params.unparsedResults - Array of data objects containing Fields(keys) - * and corresponding values of the fields(values) - * @param {import("../../../types/database-schema.td").DSQL_TableSchemaType} [params.tableSchema] - Table schema - * @returns {Promise} - */ -module.exports = async function parseDbResults({ unparsedResults, tableSchema }) { - /** - * Declare variables - * - * @description Declare "results" variable - * @type {*[]} - */ - let parsedResults = []; - - const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; - const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - - try { - /** - * Declare variables - * - * @description Declare "results" variable - */ - for (let pr = 0; pr < unparsedResults.length; pr++) { - let result = unparsedResults[pr]; - - let resultFieldNames = Object.keys(result); - - for (let i = 0; i < resultFieldNames.length; i++) { - const resultFieldName = resultFieldNames[i]; - let resultFieldSchema = tableSchema?.fields[i]; - - if (resultFieldName?.match(defaultFieldsRegexp)) { - continue; - } - - let value = result[resultFieldName]; - - if (typeof value !== "number" && !value) { - // parsedResults.push(result); - continue; - } - - if (resultFieldSchema?.encrypted && value?.match(/./)) { - result[resultFieldName] = decrypt({ encryptedString: value, encryptionKey, encryptionSalt }); - } - } - - parsedResults.push(result); - } - - /** - * Declare variables - * - * @description Declare "results" variable - */ - return parsedResults; - } catch (/** @type {*} */ error) { - console.log("ERROR in parseDbResults Function =>", error.message); - return unparsedResults; - } -}; +// @ts-check + +const decrypt = require("../../../functions/decrypt"); +// @ts-ignore +const defaultFieldsRegexp = require("./defaultFieldsRegexp"); + +/** + * Parse Database results + * ============================================================================== + * @description this function takes a database results array gotten from a DB handler + * function, decrypts encrypted fields, and returns an updated array with no encrypted + * fields + * + * @param {object} params - Single object params + * @param {*[]} params.unparsedResults - Array of data objects containing Fields(keys) + * and corresponding values of the fields(values) + * @param {import("../../../types/database-schema.td").DSQL_TableSchemaType} [params.tableSchema] - Table schema + * @returns {Promise} + */ +module.exports = async function parseDbResults({ unparsedResults, tableSchema }) { + /** + * Declare variables + * + * @description Declare "results" variable + * @type {*[]} + */ + let parsedResults = []; + + const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; + const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; + + try { + /** + * Declare variables + * + * @description Declare "results" variable + */ + for (let pr = 0; pr < unparsedResults.length; pr++) { + let result = unparsedResults[pr]; + + let resultFieldNames = Object.keys(result); + + for (let i = 0; i < resultFieldNames.length; i++) { + const resultFieldName = resultFieldNames[i]; + let resultFieldSchema = tableSchema?.fields[i]; + + if (resultFieldName?.match(defaultFieldsRegexp)) { + continue; + } + + let value = result[resultFieldName]; + + if (typeof value !== "number" && !value) { + // parsedResults.push(result); + continue; + } + + if (resultFieldSchema?.encrypted && value?.match(/./)) { + result[resultFieldName] = decrypt({ encryptedString: value, encryptionKey, encryptionSalt }); + } + } + + parsedResults.push(result); + } + + /** + * Declare variables + * + * @description Declare "results" variable + */ + return parsedResults; + } catch (/** @type {*} */ error) { + console.log("ERROR in parseDbResults Function =>", error.message); + return unparsedResults; + } +}; diff --git a/engine/engine/utils/slugToCamelTitle.js b/engine/engine/utils/slugToCamelTitle.js index 4f3053e..afd6dac 100644 --- a/engine/engine/utils/slugToCamelTitle.js +++ b/engine/engine/utils/slugToCamelTitle.js @@ -1,16 +1,16 @@ -// @ts-check - -module.exports = function slugToCamelTitle(text) { - if (text) { - let addArray = text.split("-").filter((item) => item !== ""); - let camelArray = addArray.map((item) => { - return item.substr(0, 1).toUpperCase() + item.substr(1).toLowerCase(); - }); - - let parsedAddress = camelArray.join(" "); - - return parsedAddress; - } else { - return null; - } -}; +// @ts-check + +module.exports = function slugToCamelTitle(text) { + if (text) { + let addArray = text.split("-").filter((item) => item !== ""); + let camelArray = addArray.map((item) => { + return item.substr(0, 1).toUpperCase() + item.substr(1).toLowerCase(); + }); + + let parsedAddress = camelArray.join(" "); + + return parsedAddress; + } else { + return null; + } +}; diff --git a/engine/engine/utils/supplementTable.js b/engine/engine/utils/supplementTable.js index 12c3693..f023f17 100644 --- a/engine/engine/utils/supplementTable.js +++ b/engine/engine/utils/supplementTable.js @@ -1,48 +1,48 @@ -// @ts-check - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -module.exports = function supplementTable({ tableInfoArray }) { - /** - * Format tableInfoArray - * - * @description Format tableInfoArray - */ - let finalTableArray = tableInfoArray; - const defaultFields = require("../data/defaultFields.json"); - - //////////////////////////////////////// - - let primaryKeyExists = finalTableArray.filter((_field) => _field.primaryKey); - - //////////////////////////////////////// - - defaultFields.forEach((field) => { - let fieldExists = finalTableArray.filter((_field) => _field.fieldName === field.fieldName); - - if (fieldExists && fieldExists[0]) { - return; - } else if (field.fieldName === "id" && !primaryKeyExists[0]) { - finalTableArray.unshift(field); - } else { - finalTableArray.push(field); - } - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - return finalTableArray; -}; - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ +// @ts-check + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +module.exports = function supplementTable({ tableInfoArray }) { + /** + * Format tableInfoArray + * + * @description Format tableInfoArray + */ + let finalTableArray = tableInfoArray; + const defaultFields = require("../data/defaultFields.json"); + + //////////////////////////////////////// + + let primaryKeyExists = finalTableArray.filter((_field) => _field.primaryKey); + + //////////////////////////////////////// + + defaultFields.forEach((field) => { + let fieldExists = finalTableArray.filter((_field) => _field.fieldName === field.fieldName); + + if (fieldExists && fieldExists[0]) { + return; + } else if (field.fieldName === "id" && !primaryKeyExists[0]) { + finalTableArray.unshift(field); + } else { + finalTableArray.push(field); + } + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + return finalTableArray; +}; + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ diff --git a/engine/engine/utils/updateTable.js b/engine/engine/utils/updateTable.js index d59ea3f..0dac659 100644 --- a/engine/engine/utils/updateTable.js +++ b/engine/engine/utils/updateTable.js @@ -1,457 +1,457 @@ -// @ts-check - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -///////////////////////// - Update Table Function - //////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -const fs = require("fs"); -const path = require("path"); - -const defaultFieldsRegexp = /^id$|^date_created$|^date_created_code$|^date_created_timestamp$|^date_updated$|^date_updated_code$|^date_updated_timestamp$/; - -const generateColumnDescription = require("./generateColumnDescription"); -const varDatabaseDbHandler = require("./varDatabaseDbHandler"); - -const schemaPath = path.resolve(process.cwd(), "dsql.schema.json"); - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -/** - * Update table function - * ============================================================================== - * @param {object} params - Single object params - * @param {string} params.dbFullName - Database full name => "datasquirel_user_4394_db_name" - * @param {string} params.tableName - Table Name(slug) - * @param {import("../../../types/database-schema.td").DSQL_FieldSchemaType[]} params.tableInfoArray - Table Info Array - * @param {import("../../../types/database-schema.td").DSQL_DatabaseSchemaType[]} params.dbSchema - Single post - * @param {import("../../../types/database-schema.td").DSQL_IndexSchemaType[]} [params.tableIndexes] - Table Indexes - * @param {boolean} [params.clone] - Is this a newly cloned table? - * @param {number} [params.tableIndex] - The number index of the table in the dbSchema array - * - * @returns {Promise} - */ -module.exports = async function updateTable({ dbFullName, tableName, tableInfoArray, dbSchema, tableIndexes, clone, tableIndex }) { - /** - * Initialize - * ========================================== - * @description Initial setup - */ - - /** - * @description Initialize table info array. This value will be - * changing depending on if a field is renamed or not. - */ - let upToDateTableFieldsArray = tableInfoArray; - - /** - * Handle Table updates - * - * @description Try to undate table, catch error if anything goes wrong - */ - try { - /** - * @type {string[]} - * @description Table update query string array - */ - const updateTableQueryArray = []; - - /** - * @type {string[]} - * @description Constriants query string array - */ - const constraintsQueryArray = []; - - /** - * @description Push the query initial value - */ - updateTableQueryArray.push(`ALTER TABLE \`${tableName}\``); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * @type {*} - * @description All indexes from MYSQL db - */ - const allExistingIndexes = await varDatabaseDbHandler({ - queryString: `SHOW INDEXES FROM \`${tableName}\``, - database: dbFullName, - }); - - /** - * @type {*} - * @description All columns from MYSQL db - */ - const allExistingColumns = await varDatabaseDbHandler({ - queryString: `SHOW COLUMNS FROM \`${tableName}\``, - database: dbFullName, - }); - - //////////////////////////////////////// - - /** - * @type {string[]} - * @description Updated column names Array - */ - const updatedColumnsArray = []; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * @description Iterate through every existing column - */ - if (allExistingColumns) - for (let e = 0; e < allExistingColumns.length; e++) { - const { Field } = allExistingColumns[e]; - - if (Field.match(defaultFieldsRegexp)) continue; - - /** - * @description This finds out whether the fieldName corresponds with the MSQL Field name - * if the fildName doesn't match any MYSQL Field name, the field is deleted. - */ - let existingEntry = upToDateTableFieldsArray.filter((column) => column.fieldName === Field || column.originName === Field); - - if (existingEntry && existingEntry[0]) { - /** - * @description Check if Field name has been updated - */ - if (existingEntry[0].updatedField) { - updatedColumnsArray.push(existingEntry[0].fieldName); - - const renameColumn = await varDatabaseDbHandler({ - queryString: `ALTER TABLE ${tableName} RENAME COLUMN \`${existingEntry[0].originName}\` TO \`${existingEntry[0].fieldName}\``, - database: dbFullName, - }); - - console.log(`Column Renamed from "${existingEntry[0].originName}" to "${existingEntry[0].fieldName}"`); - - /** - * Update Db Schema - * =================================================== - * @description Update Db Schema after renaming column - */ - try { - const userSchemaData = dbSchema; - - const targetDbIndex = userSchemaData.findIndex((db) => db.dbFullName === dbFullName); - const targetTableIndex = userSchemaData[targetDbIndex].tables.findIndex((table) => table.tableName === tableName); - const targetFieldIndex = userSchemaData[targetDbIndex].tables[targetTableIndex].fields.findIndex((field) => field.fieldName === existingEntry[0].fieldName); - - delete userSchemaData[targetDbIndex].tables[targetTableIndex].fields[targetFieldIndex]["originName"]; - delete userSchemaData[targetDbIndex].tables[targetTableIndex].fields[targetFieldIndex]["updatedField"]; - - /** - * @description Set New Table Fields Array - */ - upToDateTableFieldsArray = userSchemaData[targetDbIndex].tables[targetTableIndex].fields; - - fs.writeFileSync(schemaPath, JSON.stringify(userSchemaData), "utf8"); - } catch (/** @type {*} */ error) { - console.log("Error in updating Table =>", error.message); - } - - //////////////////////////////////////// - } - - //////////////////////////////////////// - - continue; - - //////////////////////////////////////// - } else { - // console.log("Column Deleted =>", Field); - await varDatabaseDbHandler({ - queryString: `ALTER TABLE ${tableName} DROP COLUMN \`${Field}\``, - database: dbFullName, - }); - } - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Handle MYSQL Table Indexes - * =================================================== - * @description Iterate through each table index(if available) - * and perform operations - */ - if (allExistingIndexes) - for (let f = 0; f < allExistingIndexes.length; f++) { - const { Key_name, Index_comment } = allExistingIndexes[f]; - - /** - * @description Check if this index was specifically created - * by datasquirel - */ - if (Index_comment?.match(/schema_index/)) { - try { - const existingKeyInSchema = tableIndexes ? tableIndexes.filter((indexObject) => indexObject.alias === Key_name) : null; - if (!existingKeyInSchema?.[0]) throw new Error(`This Index(${Key_name}) Has been Deleted!`); - } catch (error) { - /** - * @description Drop Index: This happens when the MYSQL index is not - * present in the datasquirel DB schema - */ - await varDatabaseDbHandler({ - queryString: `ALTER TABLE ${tableName} DROP INDEX \`${Key_name}\``, - database: dbFullName, - }); - } - } - } - - /** - * Handle DATASQUIREL Table Indexes - * =================================================== - * @description Iterate through each datasquirel schema - * table index(if available), and perform operations - */ - if (tableIndexes && tableIndexes[0]) { - for (let g = 0; g < tableIndexes.length; g++) { - const { indexType, indexName, indexTableFields, alias } = tableIndexes[g]; - - if (!alias?.match(/./)) continue; - - /** - * @description Check for existing Index in MYSQL db - */ - try { - const existingKeyInDb = allExistingIndexes?.filter((indexObject) => indexObject.Key_name === alias); - if (!existingKeyInDb?.[0]) throw new Error("This Index Does not Exist"); - } catch (error) { - /** - * @description Create new index if determined that it - * doesn't exist in MYSQL db - */ - await varDatabaseDbHandler({ - queryString: `CREATE${indexType.match(/fullText/i) ? " FULLTEXT" : ""} INDEX \`${alias}\` ON ${tableName}(${indexTableFields - .map((nm) => nm.value) - .map((nm) => `\`${nm}\``) - .join(",")}) COMMENT 'schema_index'`, - database: dbFullName, - }); - } - } - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Handle MYSQL Foreign Keys - * =================================================== - * @description Iterate through each datasquirel schema - * table index(if available), and perform operations - */ - - /** - * @description All MSQL Foreign Keys - * @type {*} - */ - const allForeignKeys = await varDatabaseDbHandler({ - queryString: `SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_SCHEMA = '${dbFullName}' AND TABLE_NAME='${tableName}' AND CONSTRAINT_TYPE='FOREIGN KEY'`, - database: dbFullName, - }); - - if (allForeignKeys) - for (let c = 0; c < allForeignKeys.length; c++) { - const { CONSTRAINT_NAME } = allForeignKeys[c]; - - /** - * @description Skip if Key is the PRIMARY Key - */ - if (CONSTRAINT_NAME.match(/PRIMARY/)) continue; - - /** - * @description Drop all foreign Keys to avoid MYSQL errors when adding/updating - * Foreign keys - */ - const dropForeignKey = await varDatabaseDbHandler({ - queryString: `ALTER TABLE ${tableName} DROP FOREIGN KEY \`${CONSTRAINT_NAME}\``, - database: dbFullName, - }); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Handle DATASQUIREL schema fields for current table - * =================================================== - * @description Iterate through each field object and - * perform operations - */ - for (let i = 0; i < upToDateTableFieldsArray.length; i++) { - const column = upToDateTableFieldsArray[i]; - const prevColumn = upToDateTableFieldsArray[i - 1]; - const nextColumn = upToDateTableFieldsArray[i + 1]; - - const { fieldName, dataType, nullValue, primaryKey, autoIncrement, defaultValue, defaultValueLiteral, foreignKey, updatedField } = column; - - //////////////////////////////////////// - - /** - * @description Skip default fields - */ - if (fieldName.match(/^id$|^date_/)) continue; - /** - * @description Skip columns that have been updated recently - */ - // if (updatedColumnsArray.includes(fieldName)) continue; - - //////////////////////////////////////// - - let updateText = ""; - - //////////////////////////////////////// - - let existingColumnIndex; - - /** - * @description Existing MYSQL field object - */ - let existingColumn = - allExistingColumns && allExistingColumns[0] - ? allExistingColumns.filter((_column, _index) => { - if (_column.Field === fieldName) { - existingColumnIndex = _index; - return true; - } - }) - : null; - - /** - * @description Construct SQL text snippet for this field - */ - let { fieldEntryText } = generateColumnDescription({ columnData: column }); - - /** - * @description Modify Column(Field) if it already exists - * in MYSQL database - */ - if (existingColumn && existingColumn[0]?.Field) { - const { Field, Type, Null, Key, Default, Extra } = existingColumn[0]; - - let isColumnReordered = existingColumnIndex ? i < existingColumnIndex : false; - - if (Field === fieldName && !isColumnReordered && dataType.toUpperCase() === Type.toUpperCase()) { - updateText += `MODIFY COLUMN ${fieldEntryText}`; - // continue; - } else { - updateText += `MODIFY COLUMN ${fieldEntryText}${isColumnReordered ? (prevColumn?.fieldName ? " AFTER `" + prevColumn.fieldName + "`" : " AFTER `id`") : ""}`; - // if (userId) { - // } else { - // updateText += `MODIFY COLUMN ${fieldEntryText}`; - // } - } - } else if (prevColumn && prevColumn.fieldName) { - /** - * @description Add new Column AFTER previous column, if - * previous column exists - */ - updateText += `ADD COLUMN ${fieldEntryText} AFTER \`${prevColumn.fieldName}\``; - } else if (!prevColumn && nextColumn && nextColumn.fieldName) { - /** - * @description Add new Column before next column, if - * next column exists - */ - updateText += `ADD COLUMN ${fieldEntryText} AFTER \`id\``; - } else { - /** - * @description Append new column to the end of existing columns - */ - updateText += `ADD COLUMN ${fieldEntryText}`; - } - - //////////////////////////////////////// - - /** - * @description Pust SQL code snippet to updateTableQueryArray Array - * Add a comma(,) to separate from the next snippet - */ - updateTableQueryArray.push(updateText + ","); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * @description Handle foreing keys if available, and if there is no - * "clone" boolean = true - */ - if (!clone && foreignKey) { - const { destinationTableName, destinationTableColumnName, cascadeDelete, cascadeUpdate, foreignKeyName } = foreignKey; - - const foreinKeyText = `ADD CONSTRAINT \`${foreignKeyName}\` FOREIGN KEY (${fieldName}) REFERENCES ${destinationTableName}(${destinationTableColumnName})${cascadeDelete ? " ON DELETE CASCADE" : ""}${cascadeUpdate ? " ON UPDATE CASCADE" : ""}`; - // const foreinKeyText = `ADD CONSTRAINT \`${foreignKeyName}\` FOREIGN KEY (${fieldName}) REFERENCES ${destinationTableName}(${destinationTableColumnName})${cascadeDelete ? " ON DELETE CASCADE" : ""}${cascadeUpdate ? " ON UPDATE CASCADE" : ""}` + ","; - - const finalQueryString = `ALTER TABLE \`${tableName}\` ${foreinKeyText}`; - - const addForeignKey = await varDatabaseDbHandler({ - database: dbFullName, - queryString: finalQueryString, - }); - } - - //////////////////////////////////////// - } - - /** - * @description Construct final SQL query by combning all SQL snippets in - * updateTableQueryArray Arry, and trimming the final comma(,) - */ - const updateTableQuery = updateTableQueryArray.join(" ").replace(/,$/, ""); - - //////////////////////////////////////// - - /** - * @description Check if SQL snippets array has more than 1 entries - * This is because 1 entry means "ALTER TABLE table_name" only, without any - * Alter directives like "ADD COLUMN" or "MODIFY COLUMN" - */ - if (updateTableQueryArray.length > 1) { - const updateTable = await varDatabaseDbHandler({ - queryString: updateTableQuery, - database: dbFullName, - }); - - return updateTable; - } else { - /** - * @description If only 1 SQL snippet is left in updateTableQueryArray, this - * means that no updates have been made to the table - */ - return "No Changes Made to Table"; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log('Error in "updateTable" function =>', error.message); - - return "Error in Updating Table"; - } -}; - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// +// @ts-check + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +///////////////////////// - Update Table Function - //////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +const fs = require("fs"); +const path = require("path"); + +const defaultFieldsRegexp = /^id$|^date_created$|^date_created_code$|^date_created_timestamp$|^date_updated$|^date_updated_code$|^date_updated_timestamp$/; + +const generateColumnDescription = require("./generateColumnDescription"); +const varDatabaseDbHandler = require("./varDatabaseDbHandler"); + +const schemaPath = path.resolve(process.cwd(), "dsql.schema.json"); + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Update table function + * ============================================================================== + * @param {object} params - Single object params + * @param {string} params.dbFullName - Database full name => "datasquirel_user_4394_db_name" + * @param {string} params.tableName - Table Name(slug) + * @param {import("../../../types/database-schema.td").DSQL_FieldSchemaType[]} params.tableInfoArray - Table Info Array + * @param {import("../../../types/database-schema.td").DSQL_DatabaseSchemaType[]} params.dbSchema - Single post + * @param {import("../../../types/database-schema.td").DSQL_IndexSchemaType[]} [params.tableIndexes] - Table Indexes + * @param {boolean} [params.clone] - Is this a newly cloned table? + * @param {number} [params.tableIndex] - The number index of the table in the dbSchema array + * + * @returns {Promise} + */ +module.exports = async function updateTable({ dbFullName, tableName, tableInfoArray, dbSchema, tableIndexes, clone, tableIndex }) { + /** + * Initialize + * ========================================== + * @description Initial setup + */ + + /** + * @description Initialize table info array. This value will be + * changing depending on if a field is renamed or not. + */ + let upToDateTableFieldsArray = tableInfoArray; + + /** + * Handle Table updates + * + * @description Try to undate table, catch error if anything goes wrong + */ + try { + /** + * @type {string[]} + * @description Table update query string array + */ + const updateTableQueryArray = []; + + /** + * @type {string[]} + * @description Constriants query string array + */ + const constraintsQueryArray = []; + + /** + * @description Push the query initial value + */ + updateTableQueryArray.push(`ALTER TABLE \`${tableName}\``); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * @type {*} + * @description All indexes from MYSQL db + */ + const allExistingIndexes = await varDatabaseDbHandler({ + queryString: `SHOW INDEXES FROM \`${tableName}\``, + database: dbFullName, + }); + + /** + * @type {*} + * @description All columns from MYSQL db + */ + const allExistingColumns = await varDatabaseDbHandler({ + queryString: `SHOW COLUMNS FROM \`${tableName}\``, + database: dbFullName, + }); + + //////////////////////////////////////// + + /** + * @type {string[]} + * @description Updated column names Array + */ + const updatedColumnsArray = []; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * @description Iterate through every existing column + */ + if (allExistingColumns) + for (let e = 0; e < allExistingColumns.length; e++) { + const { Field } = allExistingColumns[e]; + + if (Field.match(defaultFieldsRegexp)) continue; + + /** + * @description This finds out whether the fieldName corresponds with the MSQL Field name + * if the fildName doesn't match any MYSQL Field name, the field is deleted. + */ + let existingEntry = upToDateTableFieldsArray.filter((column) => column.fieldName === Field || column.originName === Field); + + if (existingEntry && existingEntry[0]) { + /** + * @description Check if Field name has been updated + */ + if (existingEntry[0].updatedField) { + updatedColumnsArray.push(existingEntry[0].fieldName); + + const renameColumn = await varDatabaseDbHandler({ + queryString: `ALTER TABLE ${tableName} RENAME COLUMN \`${existingEntry[0].originName}\` TO \`${existingEntry[0].fieldName}\``, + database: dbFullName, + }); + + console.log(`Column Renamed from "${existingEntry[0].originName}" to "${existingEntry[0].fieldName}"`); + + /** + * Update Db Schema + * =================================================== + * @description Update Db Schema after renaming column + */ + try { + const userSchemaData = dbSchema; + + const targetDbIndex = userSchemaData.findIndex((db) => db.dbFullName === dbFullName); + const targetTableIndex = userSchemaData[targetDbIndex].tables.findIndex((table) => table.tableName === tableName); + const targetFieldIndex = userSchemaData[targetDbIndex].tables[targetTableIndex].fields.findIndex((field) => field.fieldName === existingEntry[0].fieldName); + + delete userSchemaData[targetDbIndex].tables[targetTableIndex].fields[targetFieldIndex]["originName"]; + delete userSchemaData[targetDbIndex].tables[targetTableIndex].fields[targetFieldIndex]["updatedField"]; + + /** + * @description Set New Table Fields Array + */ + upToDateTableFieldsArray = userSchemaData[targetDbIndex].tables[targetTableIndex].fields; + + fs.writeFileSync(schemaPath, JSON.stringify(userSchemaData), "utf8"); + } catch (/** @type {*} */ error) { + console.log("Error in updating Table =>", error.message); + } + + //////////////////////////////////////// + } + + //////////////////////////////////////// + + continue; + + //////////////////////////////////////// + } else { + // console.log("Column Deleted =>", Field); + await varDatabaseDbHandler({ + queryString: `ALTER TABLE ${tableName} DROP COLUMN \`${Field}\``, + database: dbFullName, + }); + } + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Handle MYSQL Table Indexes + * =================================================== + * @description Iterate through each table index(if available) + * and perform operations + */ + if (allExistingIndexes) + for (let f = 0; f < allExistingIndexes.length; f++) { + const { Key_name, Index_comment } = allExistingIndexes[f]; + + /** + * @description Check if this index was specifically created + * by datasquirel + */ + if (Index_comment?.match(/schema_index/)) { + try { + const existingKeyInSchema = tableIndexes ? tableIndexes.filter((indexObject) => indexObject.alias === Key_name) : null; + if (!existingKeyInSchema?.[0]) throw new Error(`This Index(${Key_name}) Has been Deleted!`); + } catch (error) { + /** + * @description Drop Index: This happens when the MYSQL index is not + * present in the datasquirel DB schema + */ + await varDatabaseDbHandler({ + queryString: `ALTER TABLE ${tableName} DROP INDEX \`${Key_name}\``, + database: dbFullName, + }); + } + } + } + + /** + * Handle DATASQUIREL Table Indexes + * =================================================== + * @description Iterate through each datasquirel schema + * table index(if available), and perform operations + */ + if (tableIndexes && tableIndexes[0]) { + for (let g = 0; g < tableIndexes.length; g++) { + const { indexType, indexName, indexTableFields, alias } = tableIndexes[g]; + + if (!alias?.match(/./)) continue; + + /** + * @description Check for existing Index in MYSQL db + */ + try { + const existingKeyInDb = allExistingIndexes?.filter((indexObject) => indexObject.Key_name === alias); + if (!existingKeyInDb?.[0]) throw new Error("This Index Does not Exist"); + } catch (error) { + /** + * @description Create new index if determined that it + * doesn't exist in MYSQL db + */ + await varDatabaseDbHandler({ + queryString: `CREATE${indexType.match(/fullText/i) ? " FULLTEXT" : ""} INDEX \`${alias}\` ON ${tableName}(${indexTableFields + .map((nm) => nm.value) + .map((nm) => `\`${nm}\``) + .join(",")}) COMMENT 'schema_index'`, + database: dbFullName, + }); + } + } + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Handle MYSQL Foreign Keys + * =================================================== + * @description Iterate through each datasquirel schema + * table index(if available), and perform operations + */ + + /** + * @description All MSQL Foreign Keys + * @type {*} + */ + const allForeignKeys = await varDatabaseDbHandler({ + queryString: `SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_SCHEMA = '${dbFullName}' AND TABLE_NAME='${tableName}' AND CONSTRAINT_TYPE='FOREIGN KEY'`, + database: dbFullName, + }); + + if (allForeignKeys) + for (let c = 0; c < allForeignKeys.length; c++) { + const { CONSTRAINT_NAME } = allForeignKeys[c]; + + /** + * @description Skip if Key is the PRIMARY Key + */ + if (CONSTRAINT_NAME.match(/PRIMARY/)) continue; + + /** + * @description Drop all foreign Keys to avoid MYSQL errors when adding/updating + * Foreign keys + */ + const dropForeignKey = await varDatabaseDbHandler({ + queryString: `ALTER TABLE ${tableName} DROP FOREIGN KEY \`${CONSTRAINT_NAME}\``, + database: dbFullName, + }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Handle DATASQUIREL schema fields for current table + * =================================================== + * @description Iterate through each field object and + * perform operations + */ + for (let i = 0; i < upToDateTableFieldsArray.length; i++) { + const column = upToDateTableFieldsArray[i]; + const prevColumn = upToDateTableFieldsArray[i - 1]; + const nextColumn = upToDateTableFieldsArray[i + 1]; + + const { fieldName, dataType, nullValue, primaryKey, autoIncrement, defaultValue, defaultValueLiteral, foreignKey, updatedField } = column; + + //////////////////////////////////////// + + /** + * @description Skip default fields + */ + if (fieldName.match(/^id$|^date_/)) continue; + /** + * @description Skip columns that have been updated recently + */ + // if (updatedColumnsArray.includes(fieldName)) continue; + + //////////////////////////////////////// + + let updateText = ""; + + //////////////////////////////////////// + + let existingColumnIndex; + + /** + * @description Existing MYSQL field object + */ + let existingColumn = + allExistingColumns && allExistingColumns[0] + ? allExistingColumns.filter((_column, _index) => { + if (_column.Field === fieldName) { + existingColumnIndex = _index; + return true; + } + }) + : null; + + /** + * @description Construct SQL text snippet for this field + */ + let { fieldEntryText } = generateColumnDescription({ columnData: column }); + + /** + * @description Modify Column(Field) if it already exists + * in MYSQL database + */ + if (existingColumn && existingColumn[0]?.Field) { + const { Field, Type, Null, Key, Default, Extra } = existingColumn[0]; + + let isColumnReordered = existingColumnIndex ? i < existingColumnIndex : false; + + if (Field === fieldName && !isColumnReordered && dataType.toUpperCase() === Type.toUpperCase()) { + updateText += `MODIFY COLUMN ${fieldEntryText}`; + // continue; + } else { + updateText += `MODIFY COLUMN ${fieldEntryText}${isColumnReordered ? (prevColumn?.fieldName ? " AFTER `" + prevColumn.fieldName + "`" : " AFTER `id`") : ""}`; + // if (userId) { + // } else { + // updateText += `MODIFY COLUMN ${fieldEntryText}`; + // } + } + } else if (prevColumn && prevColumn.fieldName) { + /** + * @description Add new Column AFTER previous column, if + * previous column exists + */ + updateText += `ADD COLUMN ${fieldEntryText} AFTER \`${prevColumn.fieldName}\``; + } else if (!prevColumn && nextColumn && nextColumn.fieldName) { + /** + * @description Add new Column before next column, if + * next column exists + */ + updateText += `ADD COLUMN ${fieldEntryText} AFTER \`id\``; + } else { + /** + * @description Append new column to the end of existing columns + */ + updateText += `ADD COLUMN ${fieldEntryText}`; + } + + //////////////////////////////////////// + + /** + * @description Pust SQL code snippet to updateTableQueryArray Array + * Add a comma(,) to separate from the next snippet + */ + updateTableQueryArray.push(updateText + ","); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * @description Handle foreing keys if available, and if there is no + * "clone" boolean = true + */ + if (!clone && foreignKey) { + const { destinationTableName, destinationTableColumnName, cascadeDelete, cascadeUpdate, foreignKeyName } = foreignKey; + + const foreinKeyText = `ADD CONSTRAINT \`${foreignKeyName}\` FOREIGN KEY (${fieldName}) REFERENCES ${destinationTableName}(${destinationTableColumnName})${cascadeDelete ? " ON DELETE CASCADE" : ""}${cascadeUpdate ? " ON UPDATE CASCADE" : ""}`; + // const foreinKeyText = `ADD CONSTRAINT \`${foreignKeyName}\` FOREIGN KEY (${fieldName}) REFERENCES ${destinationTableName}(${destinationTableColumnName})${cascadeDelete ? " ON DELETE CASCADE" : ""}${cascadeUpdate ? " ON UPDATE CASCADE" : ""}` + ","; + + const finalQueryString = `ALTER TABLE \`${tableName}\` ${foreinKeyText}`; + + const addForeignKey = await varDatabaseDbHandler({ + database: dbFullName, + queryString: finalQueryString, + }); + } + + //////////////////////////////////////// + } + + /** + * @description Construct final SQL query by combning all SQL snippets in + * updateTableQueryArray Arry, and trimming the final comma(,) + */ + const updateTableQuery = updateTableQueryArray.join(" ").replace(/,$/, ""); + + //////////////////////////////////////// + + /** + * @description Check if SQL snippets array has more than 1 entries + * This is because 1 entry means "ALTER TABLE table_name" only, without any + * Alter directives like "ADD COLUMN" or "MODIFY COLUMN" + */ + if (updateTableQueryArray.length > 1) { + const updateTable = await varDatabaseDbHandler({ + queryString: updateTableQuery, + database: dbFullName, + }); + + return updateTable; + } else { + /** + * @description If only 1 SQL snippet is left in updateTableQueryArray, this + * means that no updates have been made to the table + */ + return "No Changes Made to Table"; + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } catch (/** @type {*} */ error) { + console.log('Error in "updateTable" function =>', error.message); + + return "Error in Updating Table"; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// diff --git a/engine/engine/utils/varDatabaseDbHandler.js b/engine/engine/utils/varDatabaseDbHandler.js index 19682f5..223ea70 100644 --- a/engine/engine/utils/varDatabaseDbHandler.js +++ b/engine/engine/utils/varDatabaseDbHandler.js @@ -1,98 +1,98 @@ -/** # MODULE TRACE -====================================================================== - * Detected 9 files that call this module. The files are listed below: -====================================================================== - * `require` Statement Found in [createDbFromSchema.js](d:\GitHub\dsql\engine\engine\createDbFromSchema.js) - * `require` Statement Found in [updateTable.js](d:\GitHub\dsql\engine\engine\utils\updateTable.js) - * `require` Statement Found in [runQuery.js](d:\GitHub\dsql\engine\query\utils\runQuery.js) - * `require` Statement Found in [add-user.js](d:\GitHub\dsql\engine\user\add-user.js) - * `require` Statement Found in [get-user.js](d:\GitHub\dsql\engine\user\get-user.js) - * `require` Statement Found in [login-user.js](d:\GitHub\dsql\engine\user\login-user.js) - * `require` Statement Found in [reauth-user.js](d:\GitHub\dsql\engine\user\reauth-user.js) - * `require` Statement Found in [handleSocialDb.js](d:\GitHub\dsql\engine\user\social\utils\handleSocialDb.js) - * `require` Statement Found in [update-user.js](d:\GitHub\dsql\engine\user\update-user.js) -==== MODULE TRACE END ==== */ - -// @ts-check - -const fs = require("fs"); -const parseDbResults = require("./parseDbResults"); -const dbHandler = require("./dbHandler"); - -/** - * DB handler for specific database - * ============================================================================== - * @async - * @param {object} params - Single object params - * @param {string} params.queryString - SQL string - * @param {string[]} [params.queryValuesArray] - Values Array - * @param {string} params.database - Database name - * @param {import("../../../types/database-schema.td").DSQL_TableSchemaType} [params.tableSchema] - Table schema - * @returns {Promise<*>} - */ -module.exports = async function varDatabaseDbHandler({ queryString, queryValuesArray, database, tableSchema }) { - /** - * Create Connection - * - * @description Create Connection - */ - - const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; - const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - - /** - * Declare variables - * - * @description Declare "results" variable - * @type {*} - */ - let results; - - /** - * Fetch from db - * - * @description Fetch data from db if no cache - */ - try { - if (queryString && Array.isArray(queryValuesArray) && queryValuesArray[0]) { - results = await dbHandler({ query: queryString, values: queryValuesArray, database: database }); - } else if (queryString && !Array.isArray(queryValuesArray)) { - results = await dbHandler({ query: queryString, database: database }); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } catch (error) { - console.log("\x1b[31mvarDatabaseDbHandler ERROR\x1b[0m =>", database, error); - } - - /** - * Return results - * - * @description Return results add to cache if "req" param is passed - */ - if (results && tableSchema) { - try { - const unparsedResults = results; - // deepcode ignore reDOS: - const parsedResults = await parseDbResults({ unparsedResults: unparsedResults, tableSchema: tableSchema }); - return parsedResults; - } catch (error) { - console.log("\x1b[31mvarDatabaseDbHandler ERROR\x1b[0m =>", database, error); - return null; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } else if (results) { - return results; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } else { - return null; - } -}; +/** # MODULE TRACE +====================================================================== + * Detected 9 files that call this module. The files are listed below: +====================================================================== + * `require` Statement Found in [createDbFromSchema.js](d:\GitHub\dsql\engine\engine\createDbFromSchema.js) + * `require` Statement Found in [updateTable.js](d:\GitHub\dsql\engine\engine\utils\updateTable.js) + * `require` Statement Found in [runQuery.js](d:\GitHub\dsql\engine\query\utils\runQuery.js) + * `require` Statement Found in [add-user.js](d:\GitHub\dsql\engine\user\add-user.js) + * `require` Statement Found in [get-user.js](d:\GitHub\dsql\engine\user\get-user.js) + * `require` Statement Found in [login-user.js](d:\GitHub\dsql\engine\user\login-user.js) + * `require` Statement Found in [reauth-user.js](d:\GitHub\dsql\engine\user\reauth-user.js) + * `require` Statement Found in [handleSocialDb.js](d:\GitHub\dsql\engine\user\social\utils\handleSocialDb.js) + * `require` Statement Found in [update-user.js](d:\GitHub\dsql\engine\user\update-user.js) +==== MODULE TRACE END ==== */ + +// @ts-check + +const fs = require("fs"); +const parseDbResults = require("./parseDbResults"); +const dbHandler = require("./dbHandler"); + +/** + * DB handler for specific database + * ============================================================================== + * @async + * @param {object} params - Single object params + * @param {string} params.queryString - SQL string + * @param {string[]} [params.queryValuesArray] - Values Array + * @param {string} params.database - Database name + * @param {import("../../../types/database-schema.td").DSQL_TableSchemaType} [params.tableSchema] - Table schema + * @returns {Promise<*>} + */ +module.exports = async function varDatabaseDbHandler({ queryString, queryValuesArray, database, tableSchema }) { + /** + * Create Connection + * + * @description Create Connection + */ + + const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; + const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; + + /** + * Declare variables + * + * @description Declare "results" variable + * @type {*} + */ + let results; + + /** + * Fetch from db + * + * @description Fetch data from db if no cache + */ + try { + if (queryString && Array.isArray(queryValuesArray) && queryValuesArray[0]) { + results = await dbHandler({ query: queryString, values: queryValuesArray, database: database }); + } else if (queryString && !Array.isArray(queryValuesArray)) { + results = await dbHandler({ query: queryString, database: database }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } catch (error) { + console.log("\x1b[31mvarDatabaseDbHandler ERROR\x1b[0m =>", database, error); + } + + /** + * Return results + * + * @description Return results add to cache if "req" param is passed + */ + if (results && tableSchema) { + try { + const unparsedResults = results; + // deepcode ignore reDOS: + const parsedResults = await parseDbResults({ unparsedResults: unparsedResults, tableSchema: tableSchema }); + return parsedResults; + } catch (error) { + console.log("\x1b[31mvarDatabaseDbHandler ERROR\x1b[0m =>", database, error); + return null; + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } else if (results) { + return results; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } else { + return null; + } +}; diff --git a/engine/query/get.js b/engine/query/get.js index 0907deb..2a2c9ae 100644 --- a/engine/query/get.js +++ b/engine/query/get.js @@ -1,101 +1,101 @@ -/** # MODULE TRACE -====================================================================== - * No imports found for this Module -==== MODULE TRACE END ==== */ - -// @ts-check - -const runQuery = require("./utils/runQuery"); - -/** - * @typedef {Object} LocalGetReturn - * @property {boolean} success - Did the function run successfully? - * @property {*} [payload] - GET request results - * @property {string} [msg] - Message - * @property {string} [error] - Error Message - */ - -/** - * @typedef {Object} LocalQueryObject - * @property {string} 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 {LocalQueryObject} 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 localGet({ options, dbSchema }) { - try { - const { query, queryValues } = options; - - /** @type {string | undefined | any } */ - const tableName = options?.tableName ? options.tableName : undefined; - - const dbFullName = process.env.DSQL_DB_NAME || ""; - - /** - * Input Validation - * - * @description Input Validation - */ - if (typeof query == "string" && (query.match(/^alter|^delete|information_schema|databases|^create/i) || !query.match(/^select/i))) { - return { success: false, msg: "Wrong Input" }; - } - - /** - * Create new user folder and file - * - * @description Create new user folder and file - */ - let results; - - try { - let { result, error } = await runQuery({ - dbFullName: dbFullName, - query: query, - queryValuesArray: queryValues, - dbSchema, - tableName, - }); - - if (error) throw error; - if (!result) throw new Error("No Result received for query => " + query); - if (result?.error) throw new Error(result.error); - - results = result; - return { success: true, payload: results }; - - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - //////////////////////////////////////// - - console.log("Error in local get Request =>", error.message); - - return { - success: false, - payload: null, - error: error.message, - }; - } - - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - //////////////////////////////////////// - console.log("Error in local get Request =>", error.message); - - return { success: false, msg: "Something went wrong!" }; - - //////////////////////////////////////// - } -} - -module.exports = localGet; +/** # MODULE TRACE +====================================================================== + * No imports found for this Module +==== MODULE TRACE END ==== */ + +// @ts-check + +const runQuery = require("./utils/runQuery"); + +/** + * @typedef {Object} LocalGetReturn + * @property {boolean} success - Did the function run successfully? + * @property {*} [payload] - GET request results + * @property {string} [msg] - Message + * @property {string} [error] - Error Message + */ + +/** + * @typedef {Object} LocalQueryObject + * @property {string} 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 {LocalQueryObject} 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 localGet({ options, dbSchema }) { + try { + const { query, queryValues } = options; + + /** @type {string | undefined | any } */ + const tableName = options?.tableName ? options.tableName : undefined; + + const dbFullName = process.env.DSQL_DB_NAME || ""; + + /** + * Input Validation + * + * @description Input Validation + */ + if (typeof query == "string" && (query.match(/^alter|^delete|information_schema|databases|^create/i) || !query.match(/^select/i))) { + return { success: false, msg: "Wrong Input" }; + } + + /** + * Create new user folder and file + * + * @description Create new user folder and file + */ + let results; + + try { + let { result, error } = await runQuery({ + dbFullName: dbFullName, + query: query, + queryValuesArray: queryValues, + dbSchema, + tableName, + }); + + if (error) throw error; + if (!result) throw new Error("No Result received for query => " + query); + if (result?.error) throw new Error(result.error); + + results = result; + return { success: true, payload: results }; + + //////////////////////////////////////// + } catch (/** @type {*} */ error) { + //////////////////////////////////////// + + console.log("Error in local get Request =>", error.message); + + return { + success: false, + payload: null, + error: error.message, + }; + } + + //////////////////////////////////////// + } catch (/** @type {*} */ error) { + //////////////////////////////////////// + console.log("Error in local get Request =>", error.message); + + return { success: false, msg: "Something went wrong!" }; + + //////////////////////////////////////// + } +} + +module.exports = localGet; diff --git a/engine/query/post.js b/engine/query/post.js index 671a96e..b6b2e66 100644 --- a/engine/query/post.js +++ b/engine/query/post.js @@ -1,100 +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 (/** @type {*} */ error) { - //////////////////////////////////////// - - return { - success: false, - payload: null, - error: error.message, - }; - } - - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - //////////////////////////////////////// - console.log("Error in local post Request =>", error.message); - - return { - success: false, - payload: null, - msg: "Something went wrong!", - }; - - //////////////////////////////////////// - } -} - -module.exports = localPost; +// @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 (/** @type {*} */ error) { + //////////////////////////////////////// + + return { + success: false, + payload: null, + error: error.message, + }; + } + + //////////////////////////////////////// + } catch (/** @type {*} */ 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 index 07d8131..a6489cb 100644 --- a/engine/query/update-api-schema-from-local-db.js +++ b/engine/query/update-api-schema-from-local-db.js @@ -1,143 +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 (/** @type {*} */ error) { - return { - success: false, - payload: null, - error: error.message, - }; - } -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = updateApiSchemaFromLocalDb; +// @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 (/** @type {*} */ error) { + return { + success: false, + payload: null, + error: error.message, + }; + } +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = updateApiSchemaFromLocalDb; diff --git a/engine/query/utils/addDbEntry.js b/engine/query/utils/addDbEntry.js index f50c56c..08b08d1 100644 --- a/engine/query/utils/addDbEntry.js +++ b/engine/query/utils/addDbEntry.js @@ -1,162 +1,162 @@ -// @ts-check - -/** - * Imports: Handle imports - */ -const encrypt = require("../../../functions/encrypt"); -const dbHandler = require("../../engine/utils/dbHandler"); -const updateDb = require("./updateDbEntry"); -const updateDbEntry = require("./updateDbEntry"); - -/** - * Add a db Entry Function - * ============================================================================== - * @description Description - * @async - * - * @param {object} params - An object containing the function parameters. - * "Read only" or "Full Access"? Defaults to "Read Only" - * @param {string} params.dbFullName - Database full name - * @param {string} params.tableName - Table name - * @param {*} params.data - Data to add - * @param {import("../../../types/database-schema.td").DSQL_TableSchemaType} [params.tableSchema] - Table schema - * @param {string} [params.duplicateColumnName] - Duplicate column name - * @param {string} [params.duplicateColumnValue] - Duplicate column value - * @param {boolean} [params.update] - Update this row if it exists - * @param {string} params.encryptionKey - Update this row if it exists - * @param {string} params.encryptionSalt - Update this row if it exists - * - * @returns {Promise<*>} - */ -async function addDbEntry({ dbFullName, tableName, data, tableSchema, duplicateColumnName, duplicateColumnValue, update, encryptionKey, encryptionSalt }) { - /** - * Initialize variables - */ - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Handle function logic - */ - - if (duplicateColumnName && typeof duplicateColumnName === "string") { - const duplicateValue = await dbHandler({ - database: dbFullName, - query: `SELECT * FROM \`${tableName}\` WHERE \`${duplicateColumnName}\`=?`, - values: [duplicateColumnValue || ""], - }); - - if (duplicateValue && duplicateValue[0] && !update) { - return null; - } else if (duplicateValue && duplicateValue[0] && update) { - return await updateDbEntry({ - dbFullName, - tableName, - data, - tableSchema, - identifierColumnName: duplicateColumnName, - identifierValue: duplicateColumnValue || "", - encryptionKey, - encryptionSalt, - }); - } - } - - /** - * Declare variables - * - * @description Declare "results" variable - */ - const dataKeys = Object.keys(data); - - let insertKeysArray = []; - let insertValuesArray = []; - - for (let i = 0; i < dataKeys.length; i++) { - try { - const dataKey = dataKeys[i]; - let value = data[dataKey]; - - const targetFieldSchemaArray = tableSchema ? tableSchema?.fields?.filter((field) => field.fieldName == dataKey) : null; - const targetFieldSchema = targetFieldSchemaArray && targetFieldSchemaArray[0] ? targetFieldSchemaArray[0] : null; - - if (!value) continue; - - if (targetFieldSchema?.encrypted) { - value = encrypt({ data: value, encryptionKey, encryptionSalt }); - console.log("DSQL: Encrypted value =>", value); - } - - if (targetFieldSchema?.pattern) { - const pattern = new RegExp(targetFieldSchema.pattern, targetFieldSchema.patternFlags || ""); - if (!value?.toString()?.match(pattern)) { - console.log("DSQL: Pattern not matched =>", value); - value = ""; - } - } - - if (typeof value === "string" && !value.match(/./i)) { - value = { - toSqlString: function () { - return "NULL"; - }, - }; - } - - insertKeysArray.push("`" + dataKey + "`"); - - if (typeof value === "object") { - value = JSON.stringify(value); - } - - insertValuesArray.push(value); - } catch (/** @type {*} */ error) { - console.log("DSQL: Error in parsing data keys =>", error.message); - continue; - } - } - - //////////////////////////////////////// - - insertKeysArray.push("`date_created`"); - insertValuesArray.push(Date()); - - insertKeysArray.push("`date_created_code`"); - insertValuesArray.push(Date.now()); - - //////////////////////////////////////// - - insertKeysArray.push("`date_updated`"); - insertValuesArray.push(Date()); - - insertKeysArray.push("`date_updated_code`"); - insertValuesArray.push(Date.now()); - - //////////////////////////////////////// - - const query = `INSERT INTO \`${tableName}\` (${insertKeysArray.join(",")}) VALUES (${insertValuesArray.map(() => "?").join(",")})`; - const queryValuesArray = insertValuesArray; - - const newInsert = await dbHandler({ - database: dbFullName, - query: query, - values: queryValuesArray, - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Return statement - */ - return newInsert; -} - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -module.exports = addDbEntry; +// @ts-check + +/** + * Imports: Handle imports + */ +const encrypt = require("../../../functions/encrypt"); +const dbHandler = require("../../engine/utils/dbHandler"); +const updateDb = require("./updateDbEntry"); +const updateDbEntry = require("./updateDbEntry"); + +/** + * Add a db Entry Function + * ============================================================================== + * @description Description + * @async + * + * @param {object} params - An object containing the function parameters. + * "Read only" or "Full Access"? Defaults to "Read Only" + * @param {string} params.dbFullName - Database full name + * @param {string} params.tableName - Table name + * @param {*} params.data - Data to add + * @param {import("../../../types/database-schema.td").DSQL_TableSchemaType} [params.tableSchema] - Table schema + * @param {string} [params.duplicateColumnName] - Duplicate column name + * @param {string} [params.duplicateColumnValue] - Duplicate column value + * @param {boolean} [params.update] - Update this row if it exists + * @param {string} params.encryptionKey - Update this row if it exists + * @param {string} params.encryptionSalt - Update this row if it exists + * + * @returns {Promise<*>} + */ +async function addDbEntry({ dbFullName, tableName, data, tableSchema, duplicateColumnName, duplicateColumnValue, update, encryptionKey, encryptionSalt }) { + /** + * Initialize variables + */ + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Handle function logic + */ + + if (duplicateColumnName && typeof duplicateColumnName === "string") { + const duplicateValue = await dbHandler({ + database: dbFullName, + query: `SELECT * FROM \`${tableName}\` WHERE \`${duplicateColumnName}\`=?`, + values: [duplicateColumnValue || ""], + }); + + if (duplicateValue && duplicateValue[0] && !update) { + return null; + } else if (duplicateValue && duplicateValue[0] && update) { + return await updateDbEntry({ + dbFullName, + tableName, + data, + tableSchema, + identifierColumnName: duplicateColumnName, + identifierValue: duplicateColumnValue || "", + encryptionKey, + encryptionSalt, + }); + } + } + + /** + * Declare variables + * + * @description Declare "results" variable + */ + const dataKeys = Object.keys(data); + + let insertKeysArray = []; + let insertValuesArray = []; + + for (let i = 0; i < dataKeys.length; i++) { + try { + const dataKey = dataKeys[i]; + let value = data[dataKey]; + + const targetFieldSchemaArray = tableSchema ? tableSchema?.fields?.filter((field) => field.fieldName == dataKey) : null; + const targetFieldSchema = targetFieldSchemaArray && targetFieldSchemaArray[0] ? targetFieldSchemaArray[0] : null; + + if (!value) continue; + + if (targetFieldSchema?.encrypted) { + value = encrypt({ data: value, encryptionKey, encryptionSalt }); + console.log("DSQL: Encrypted value =>", value); + } + + if (targetFieldSchema?.pattern) { + const pattern = new RegExp(targetFieldSchema.pattern, targetFieldSchema.patternFlags || ""); + if (!value?.toString()?.match(pattern)) { + console.log("DSQL: Pattern not matched =>", value); + value = ""; + } + } + + if (typeof value === "string" && !value.match(/./i)) { + value = { + toSqlString: function () { + return "NULL"; + }, + }; + } + + insertKeysArray.push("`" + dataKey + "`"); + + if (typeof value === "object") { + value = JSON.stringify(value); + } + + insertValuesArray.push(value); + } catch (/** @type {*} */ error) { + console.log("DSQL: Error in parsing data keys =>", error.message); + continue; + } + } + + //////////////////////////////////////// + + insertKeysArray.push("`date_created`"); + insertValuesArray.push(Date()); + + insertKeysArray.push("`date_created_code`"); + insertValuesArray.push(Date.now()); + + //////////////////////////////////////// + + insertKeysArray.push("`date_updated`"); + insertValuesArray.push(Date()); + + insertKeysArray.push("`date_updated_code`"); + insertValuesArray.push(Date.now()); + + //////////////////////////////////////// + + const query = `INSERT INTO \`${tableName}\` (${insertKeysArray.join(",")}) VALUES (${insertValuesArray.map(() => "?").join(",")})`; + const queryValuesArray = insertValuesArray; + + const newInsert = await dbHandler({ + database: dbFullName, + query: query, + values: queryValuesArray, + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Return statement + */ + return newInsert; +} + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +module.exports = addDbEntry; diff --git a/engine/query/utils/deleteDbEntry.js b/engine/query/utils/deleteDbEntry.js index a31b27e..28b682c 100644 --- a/engine/query/utils/deleteDbEntry.js +++ b/engine/query/utils/deleteDbEntry.js @@ -1,76 +1,76 @@ -// @ts-check - -const dbHandler = require("../../engine/utils/dbHandler"); - -/** - * Imports: Handle imports - */ - -/** - * Delete DB Entry Function - * ============================================================================== - * @description Description - * @async - * - * @param {object} params - An object containing the function parameters. - * @param {string} [params.dbContext] - What is the database context? "Master" - * or "Dsql User". Defaults to "Master" - * @param {("Read Only" | "Full Access")} [params.paradigm] - What is the paradigm for "Dsql User"? - * "Read only" or "Full Access"? Defaults to "Read Only" - * @param {string} params.dbFullName - Database full name - * @param {string} params.tableName - Table name - * @param {import("../../../types/database-schema.td").DSQL_TableSchemaType} [params.tableSchema] - Table schema - * @param {string} params.identifierColumnName - Update row identifier column name - * @param {string|number} params.identifierValue - Update row identifier column value - * - * @returns {Promise} - */ -async function deleteDbEntry({ dbContext, paradigm, dbFullName, tableName, identifierColumnName, identifierValue }) { - try { - /** - * Check if data is valid - */ - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Execution - * - * @description - */ - const query = `DELETE FROM ${tableName} WHERE \`${identifierColumnName}\`=?`; - - const deletedEntry = await dbHandler({ - query: query, - database: dbFullName, - values: [identifierValue], - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Return statement - */ - return deletedEntry; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } catch (error) { - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - return null; - } -} - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -module.exports = deleteDbEntry; +// @ts-check + +const dbHandler = require("../../engine/utils/dbHandler"); + +/** + * Imports: Handle imports + */ + +/** + * Delete DB Entry Function + * ============================================================================== + * @description Description + * @async + * + * @param {object} params - An object containing the function parameters. + * @param {string} [params.dbContext] - What is the database context? "Master" + * or "Dsql User". Defaults to "Master" + * @param {("Read Only" | "Full Access")} [params.paradigm] - What is the paradigm for "Dsql User"? + * "Read only" or "Full Access"? Defaults to "Read Only" + * @param {string} params.dbFullName - Database full name + * @param {string} params.tableName - Table name + * @param {import("../../../types/database-schema.td").DSQL_TableSchemaType} [params.tableSchema] - Table schema + * @param {string} params.identifierColumnName - Update row identifier column name + * @param {string|number} params.identifierValue - Update row identifier column value + * + * @returns {Promise} + */ +async function deleteDbEntry({ dbContext, paradigm, dbFullName, tableName, identifierColumnName, identifierValue }) { + try { + /** + * Check if data is valid + */ + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Execution + * + * @description + */ + const query = `DELETE FROM ${tableName} WHERE \`${identifierColumnName}\`=?`; + + const deletedEntry = await dbHandler({ + query: query, + database: dbFullName, + values: [identifierValue], + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Return statement + */ + return deletedEntry; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } catch (error) { + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + return null; + } +} + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +module.exports = deleteDbEntry; diff --git a/engine/query/utils/runQuery.js b/engine/query/utils/runQuery.js index f712645..5eab214 100644 --- a/engine/query/utils/runQuery.js +++ b/engine/query/utils/runQuery.js @@ -1,165 +1,165 @@ -/** # MODULE TRACE -====================================================================== - * Detected 4 files that call this module. The files are listed below: -====================================================================== - * `require` Statement Found in [get.js](d:\GitHub\dsql\engine\query\get.js) - * `require` Statement Found in [post.js](d:\GitHub\dsql\engine\query\post.js) - * `require` Statement Found in [add-user.js](d:\GitHub\dsql\engine\user\add-user.js) - * `require` Statement Found in [update-user.js](d:\GitHub\dsql\engine\user\update-user.js) -==== MODULE TRACE END ==== */ - -// @ts-check - -const fs = require("fs"); - -const addDbEntry = require("./addDbEntry"); -const updateDbEntry = require("./updateDbEntry"); -const deleteDbEntry = require("./deleteDbEntry"); -const varDatabaseDbHandler = require("../../engine/utils/varDatabaseDbHandler"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * Run DSQL users queries - * ============================================================================== - * @param {object} params - An object containing the function parameters. - * @param {string} params.dbFullName - Database full name. Eg. "datasquire_user_2_test" - * @param {*} params.query - Query string or object - * @param {boolean} [params.readOnly] - Is this operation read only? - * @param {import("../../../types/database-schema.td").DSQL_DatabaseSchemaType} [params.dbSchema] - Database schema - * @param {string[]} [params.queryValuesArray] - An optional array of query values if "?" is used in the query string - * @param {string} [params.tableName] - Table Name - * - * @return {Promise<{result: *, error?: *}>} - */ -async function runQuery({ dbFullName, query, readOnly, dbSchema, queryValuesArray, tableName }) { - /** - * Declare variables - * - * @description Declare "results" variable - */ - const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; - const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - - let result, error, tableSchema; - - if (dbSchema) { - try { - const table = tableName ? tableName : typeof query == "string" ? null : query ? query?.table : null; - if (!table) throw new Error("No table name provided"); - tableSchema = dbSchema.tables.filter((tb) => tb?.tableName === table)[0]; - } catch (_err) {} - } - - /** - * Declare variables - * - * @description Declare "results" variable - */ - try { - if (typeof query === "string") { - result = await varDatabaseDbHandler({ - queryString: query, - queryValuesArray, - database: dbFullName, - tableSchema, - }); - } else if (typeof query === "object") { - /** - * Declare variables - * - * @description Declare "results" variable - */ - const { data, action, table, identifierColumnName, identifierValue, update, duplicateColumnName, duplicateColumnValue } = query; - - switch (action.toLowerCase()) { - case "insert": - result = await addDbEntry({ - dbFullName: dbFullName, - tableName: table, - data: data, - update, - duplicateColumnName, - duplicateColumnValue, - tableSchema, - encryptionKey, - encryptionSalt, - }); - - if (!result?.insertId) { - error = new Error("Couldn't insert data"); - } - - break; - - case "update": - result = await updateDbEntry({ - dbContext: "Dsql User", - paradigm: "Full Access", - dbFullName: dbFullName, - tableName: table, - data: data, - identifierColumnName, - identifierValue, - tableSchema, - encryptionKey, - encryptionSalt, - }); - - break; - - case "delete": - result = await deleteDbEntry({ - dbContext: "Dsql User", - paradigm: "Full Access", - dbFullName: dbFullName, - tableName: table, - identifierColumnName, - identifierValue, - tableSchema, - }); - - break; - - default: - console.log("Unhandled Query"); - console.log("Query Recieved =>", query); - result = { - result: null, - error: "Unhandled Query", - }; - break; - } - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("Error in Running Query =>", error.message); - console.log("Query Recieved =>", query); - - result = { - result: null, - error: "Error in running Query => " + error.message, - }; - error = error.message; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - return { result, error }; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// -} - -module.exports = runQuery; +/** # MODULE TRACE +====================================================================== + * Detected 4 files that call this module. The files are listed below: +====================================================================== + * `require` Statement Found in [get.js](d:\GitHub\dsql\engine\query\get.js) + * `require` Statement Found in [post.js](d:\GitHub\dsql\engine\query\post.js) + * `require` Statement Found in [add-user.js](d:\GitHub\dsql\engine\user\add-user.js) + * `require` Statement Found in [update-user.js](d:\GitHub\dsql\engine\user\update-user.js) +==== MODULE TRACE END ==== */ + +// @ts-check + +const fs = require("fs"); + +const addDbEntry = require("./addDbEntry"); +const updateDbEntry = require("./updateDbEntry"); +const deleteDbEntry = require("./deleteDbEntry"); +const varDatabaseDbHandler = require("../../engine/utils/varDatabaseDbHandler"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Run DSQL users queries + * ============================================================================== + * @param {object} params - An object containing the function parameters. + * @param {string} params.dbFullName - Database full name. Eg. "datasquire_user_2_test" + * @param {*} params.query - Query string or object + * @param {boolean} [params.readOnly] - Is this operation read only? + * @param {import("../../../types/database-schema.td").DSQL_DatabaseSchemaType} [params.dbSchema] - Database schema + * @param {string[]} [params.queryValuesArray] - An optional array of query values if "?" is used in the query string + * @param {string} [params.tableName] - Table Name + * + * @return {Promise<{result: *, error?: *}>} + */ +async function runQuery({ dbFullName, query, readOnly, dbSchema, queryValuesArray, tableName }) { + /** + * Declare variables + * + * @description Declare "results" variable + */ + const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; + const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; + + let result, error, tableSchema; + + if (dbSchema) { + try { + const table = tableName ? tableName : typeof query == "string" ? null : query ? query?.table : null; + if (!table) throw new Error("No table name provided"); + tableSchema = dbSchema.tables.filter((tb) => tb?.tableName === table)[0]; + } catch (_err) {} + } + + /** + * Declare variables + * + * @description Declare "results" variable + */ + try { + if (typeof query === "string") { + result = await varDatabaseDbHandler({ + queryString: query, + queryValuesArray, + database: dbFullName, + tableSchema, + }); + } else if (typeof query === "object") { + /** + * Declare variables + * + * @description Declare "results" variable + */ + const { data, action, table, identifierColumnName, identifierValue, update, duplicateColumnName, duplicateColumnValue } = query; + + switch (action.toLowerCase()) { + case "insert": + result = await addDbEntry({ + dbFullName: dbFullName, + tableName: table, + data: data, + update, + duplicateColumnName, + duplicateColumnValue, + tableSchema, + encryptionKey, + encryptionSalt, + }); + + if (!result?.insertId) { + error = new Error("Couldn't insert data"); + } + + break; + + case "update": + result = await updateDbEntry({ + dbContext: "Dsql User", + paradigm: "Full Access", + dbFullName: dbFullName, + tableName: table, + data: data, + identifierColumnName, + identifierValue, + tableSchema, + encryptionKey, + encryptionSalt, + }); + + break; + + case "delete": + result = await deleteDbEntry({ + dbContext: "Dsql User", + paradigm: "Full Access", + dbFullName: dbFullName, + tableName: table, + identifierColumnName, + identifierValue, + tableSchema, + }); + + break; + + default: + console.log("Unhandled Query"); + console.log("Query Recieved =>", query); + result = { + result: null, + error: "Unhandled Query", + }; + break; + } + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } catch (/** @type {*} */ error) { + console.log("Error in Running Query =>", error.message); + console.log("Query Recieved =>", query); + + result = { + result: null, + error: "Error in running Query => " + error.message, + }; + error = error.message; + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + return { result, error }; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// +} + +module.exports = runQuery; diff --git a/engine/query/utils/updateDbEntry.js b/engine/query/utils/updateDbEntry.js index 5907e7e..9b548cf 100644 --- a/engine/query/utils/updateDbEntry.js +++ b/engine/query/utils/updateDbEntry.js @@ -1,149 +1,149 @@ -// @ts-check - -const encrypt = require("../../../functions/encrypt"); -const dbHandler = require("../../engine/utils/dbHandler"); - -/** - * Imports: Handle imports - */ - -/** - * Update DB Function - * ============================================================================== - * @description Description - * @async - * - * @param {object} params - An object containing the function parameters. - * @param {("Master" | "Dsql User")} [params.dbContext] - What is the database context? "Master" - * or "Dsql User". Defaults to "Master" - * @param {("Read Only" | "Full Access")} [params.paradigm] - What is the paradigm for "Dsql User"? - * "Read only" or "Full Access"? Defaults to "Read Only" - * @param {string} params.dbFullName - Database full name - * @param {string} params.tableName - Table name - * @param {*} params.data - Data to add - * @param {import("../../../types/database-schema.td").DSQL_TableSchemaType} [params.tableSchema] - Table schema - * @param {string} params.identifierColumnName - Update row identifier column name - * @param {string | number} params.identifierValue - Update row identifier column value - * @param {string} params.encryptionKey - Encryption key - * @param {string} params.encryptionSalt - Encryption salt - * - * @returns {Promise} - */ -async function updateDbEntry({ dbContext, paradigm, dbFullName, tableName, data, tableSchema, identifierColumnName, identifierValue, encryptionKey, encryptionSalt }) { - /** - * Check if data is valid - */ - if (!data || !Object.keys(data).length) return null; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Declare variables - * - * @description Declare "results" variable - */ - const dataKeys = Object.keys(data); - - let updateKeyValueArray = []; - let updateValues = []; - - /** - * Declare variables - * - * @description Declare "results" variable - */ - for (let i = 0; i < dataKeys.length; i++) { - try { - const dataKey = dataKeys[i]; - let value = data[dataKey]; - - const targetFieldSchemaArray = tableSchema ? tableSchema?.fields?.filter((field) => field.fieldName === dataKey) : null; - const targetFieldSchema = targetFieldSchemaArray && targetFieldSchemaArray[0] ? targetFieldSchemaArray[0] : null; - - if (typeof value == "undefined") continue; - if (typeof value !== "string" && typeof value !== "number" && !value) continue; - - if (targetFieldSchema?.encrypted) { - value = encrypt({ data: value, encryptionKey, encryptionSalt }); - } - - if (typeof value === "object") { - value = JSON.stringify(value); - } - - if (typeof value === "string" && value.match(/^null$/i)) { - value = { - toSqlString: function () { - return "NULL"; - }, - }; - } - - if (targetFieldSchema?.pattern) { - const pattern = new RegExp(targetFieldSchema.pattern, targetFieldSchema.patternFlags || ""); - if (!value?.toString()?.match(pattern)) { - console.log("DSQL: Pattern not matched =>", value); - value = ""; - } - } - - if (typeof value === "string" && !value.match(/./i)) { - value = { - toSqlString: function () { - return "NULL"; - }, - }; - } - - if (!value && typeof value == "number" && value != 0) continue; - - updateKeyValueArray.push(`\`${dataKey}\`=?`); - updateValues.push(value); - - //////////////////////////////////////// - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - //////////////////////////////////////// - //////////////////////////////////////// - - console.log("DSQL: Error in parsing data keys in update function =>", error.message); - continue; - } - } - - //////////////////////////////////////// - //////////////////////////////////////// - - updateKeyValueArray.push(`date_updated='${Date()}'`); - updateKeyValueArray.push(`date_updated_code='${Date.now()}'`); - - //////////////////////////////////////// - //////////////////////////////////////// - - const query = `UPDATE ${tableName} SET ${updateKeyValueArray.join(",")} WHERE \`${identifierColumnName}\`=?`; - - updateValues.push(identifierValue); - - const updatedEntry = await dbHandler({ - database: dbFullName, - query: query, - values: updateValues, - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Return statement - */ - return updatedEntry; -} - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -module.exports = updateDbEntry; +// @ts-check + +const encrypt = require("../../../functions/encrypt"); +const dbHandler = require("../../engine/utils/dbHandler"); + +/** + * Imports: Handle imports + */ + +/** + * Update DB Function + * ============================================================================== + * @description Description + * @async + * + * @param {object} params - An object containing the function parameters. + * @param {("Master" | "Dsql User")} [params.dbContext] - What is the database context? "Master" + * or "Dsql User". Defaults to "Master" + * @param {("Read Only" | "Full Access")} [params.paradigm] - What is the paradigm for "Dsql User"? + * "Read only" or "Full Access"? Defaults to "Read Only" + * @param {string} params.dbFullName - Database full name + * @param {string} params.tableName - Table name + * @param {*} params.data - Data to add + * @param {import("../../../types/database-schema.td").DSQL_TableSchemaType} [params.tableSchema] - Table schema + * @param {string} params.identifierColumnName - Update row identifier column name + * @param {string | number} params.identifierValue - Update row identifier column value + * @param {string} params.encryptionKey - Encryption key + * @param {string} params.encryptionSalt - Encryption salt + * + * @returns {Promise} + */ +async function updateDbEntry({ dbContext, paradigm, dbFullName, tableName, data, tableSchema, identifierColumnName, identifierValue, encryptionKey, encryptionSalt }) { + /** + * Check if data is valid + */ + if (!data || !Object.keys(data).length) return null; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Declare variables + * + * @description Declare "results" variable + */ + const dataKeys = Object.keys(data); + + let updateKeyValueArray = []; + let updateValues = []; + + /** + * Declare variables + * + * @description Declare "results" variable + */ + for (let i = 0; i < dataKeys.length; i++) { + try { + const dataKey = dataKeys[i]; + let value = data[dataKey]; + + const targetFieldSchemaArray = tableSchema ? tableSchema?.fields?.filter((field) => field.fieldName === dataKey) : null; + const targetFieldSchema = targetFieldSchemaArray && targetFieldSchemaArray[0] ? targetFieldSchemaArray[0] : null; + + if (typeof value == "undefined") continue; + if (typeof value !== "string" && typeof value !== "number" && !value) continue; + + if (targetFieldSchema?.encrypted) { + value = encrypt({ data: value, encryptionKey, encryptionSalt }); + } + + if (typeof value === "object") { + value = JSON.stringify(value); + } + + if (typeof value === "string" && value.match(/^null$/i)) { + value = { + toSqlString: function () { + return "NULL"; + }, + }; + } + + if (targetFieldSchema?.pattern) { + const pattern = new RegExp(targetFieldSchema.pattern, targetFieldSchema.patternFlags || ""); + if (!value?.toString()?.match(pattern)) { + console.log("DSQL: Pattern not matched =>", value); + value = ""; + } + } + + if (typeof value === "string" && !value.match(/./i)) { + value = { + toSqlString: function () { + return "NULL"; + }, + }; + } + + if (!value && typeof value == "number" && value != 0) continue; + + updateKeyValueArray.push(`\`${dataKey}\`=?`); + updateValues.push(value); + + //////////////////////////////////////// + //////////////////////////////////////// + } catch (/** @type {*} */ error) { + //////////////////////////////////////// + //////////////////////////////////////// + + console.log("DSQL: Error in parsing data keys in update function =>", error.message); + continue; + } + } + + //////////////////////////////////////// + //////////////////////////////////////// + + updateKeyValueArray.push(`date_updated='${Date()}'`); + updateKeyValueArray.push(`date_updated_code='${Date.now()}'`); + + //////////////////////////////////////// + //////////////////////////////////////// + + const query = `UPDATE ${tableName} SET ${updateKeyValueArray.join(",")} WHERE \`${identifierColumnName}\`=?`; + + updateValues.push(identifierValue); + + const updatedEntry = await dbHandler({ + database: dbFullName, + query: query, + values: updateValues, + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Return statement + */ + return updatedEntry; +} + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +module.exports = updateDbEntry; diff --git a/engine/user/add-user.js b/engine/user/add-user.js index 9a8cbbc..bc7adc1 100644 --- a/engine/user/add-user.js +++ b/engine/user/add-user.js @@ -1,153 +1,153 @@ -// @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 || ""; - - const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; - const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - - /** - * Hash Password - * - * @description Hash Password - */ - if (!payload?.password) { - return { success: false, payload: `Password is required to create an account` }; - } - - const hashedPassword = hashPassword({ - password: payload.password, - encryptionKey, - }); - 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((/** @type {*} */ 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 tableSchema = dbSchema.tables.find((tb) => tb?.tableName === "users"); - - 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, - tableSchema: tableSchema, - }); - - if (existingUser && existingUser[0]) { - return { - success: false, - payload: "User Already Exists", - }; - } - - const addUser = await addDbEntry({ - dbFullName: dbFullName, - tableName: "users", - data: { - ...payload, - image: "/images/user_images/user-preset.png", - image_thumbnail: "/images/user_images/user-preset-thumbnail.png", - }, - encryptionKey, - encryptionSalt, - tableSchema, - }); - - 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 (/** @type {*} */ error) { - //////////////////////////////////////// - console.log("Error in local add-user Request =>", error.message); - - return { - success: false, - payload: null, - msg: "Something went wrong!", - }; - - //////////////////////////////////////// - } -} - -module.exports = localAddUser; +// @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 || ""; + + const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; + const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; + + /** + * Hash Password + * + * @description Hash Password + */ + if (!payload?.password) { + return { success: false, payload: `Password is required to create an account` }; + } + + const hashedPassword = hashPassword({ + password: payload.password, + encryptionKey, + }); + 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((/** @type {*} */ 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 tableSchema = dbSchema.tables.find((tb) => tb?.tableName === "users"); + + 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, + tableSchema: tableSchema, + }); + + if (existingUser && existingUser[0]) { + return { + success: false, + payload: "User Already Exists", + }; + } + + const addUser = await addDbEntry({ + dbFullName: dbFullName, + tableName: "users", + data: { + ...payload, + image: "/images/user_images/user-preset.png", + image_thumbnail: "/images/user_images/user-preset-thumbnail.png", + }, + encryptionKey, + encryptionSalt, + tableSchema, + }); + + 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 (/** @type {*} */ 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/engine/user/get-user.js b/engine/user/get-user.js index 8c934ff..38ce265 100644 --- a/engine/user/get-user.js +++ b/engine/user/get-user.js @@ -1,53 +1,53 @@ -// @ts-check - -const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler"); - -/** - * - * @param {object} param0 - * @param {number} param0.userId - * @param {string[]} param0.fields - * @param {import("../../types/database-schema.td").DSQL_DatabaseSchemaType} [param0.dbSchema] - * @returns - */ -async function getLocalUser({ userId, fields, dbSchema }) { - /** - * GRAB user - * - * @description GRAB user - */ - const sanitizedFields = fields.map((fld) => fld.replace(/[^a-z\_]/g, "")); - const query = `SELECT ${sanitizedFields.join(",")} FROM users WHERE id = ?`; - - const tableSchema = dbSchema?.tables.find((tb) => tb?.tableName === "users"); - - let foundUser = await varDatabaseDbHandler({ - queryString: query, - queryValuesArray: [userId.toString()], - database: process.env.DSQL_DB_NAME || "", - tableSchema, - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - if (!foundUser || !foundUser[0]) - return { - success: false, - payload: null, - msg: "User not found!", - }; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** ********************* Send Response */ - return { - success: true, - payload: foundUser[0], - }; -} - -module.exports = getLocalUser; +// @ts-check + +const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler"); + +/** + * + * @param {object} param0 + * @param {number} param0.userId + * @param {string[]} param0.fields + * @param {import("../../types/database-schema.td").DSQL_DatabaseSchemaType} [param0.dbSchema] + * @returns + */ +async function getLocalUser({ userId, fields, dbSchema }) { + /** + * GRAB user + * + * @description GRAB user + */ + const sanitizedFields = fields.map((fld) => fld.replace(/[^a-z\_]/g, "")); + const query = `SELECT ${sanitizedFields.join(",")} FROM users WHERE id = ?`; + + const tableSchema = dbSchema?.tables.find((tb) => tb?.tableName === "users"); + + let foundUser = await varDatabaseDbHandler({ + queryString: query, + queryValuesArray: [userId.toString()], + database: process.env.DSQL_DB_NAME || "", + tableSchema, + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + if (!foundUser || !foundUser[0]) + return { + success: false, + payload: null, + msg: "User not found!", + }; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** ********************* Send Response */ + return { + success: true, + payload: foundUser[0], + }; +} + +module.exports = getLocalUser; diff --git a/engine/user/login-user.js b/engine/user/login-user.js index 03508d6..8471cd7 100644 --- a/engine/user/login-user.js +++ b/engine/user/login-user.js @@ -1,152 +1,152 @@ -// @ts-check - -const hashPassword = require("../../functions/hashPassword"); -const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler"); - -/** - * - * @param {object} param0 - * @param {{ - * email?: string, - * username?: string, - * password: string, - * }} param0.payload - * @param {string[]} [param0.additionalFields] - * @param {import("../../types/database-schema.td").DSQL_DatabaseSchemaType} [param0.dbSchema] - * @returns - */ -async function loginLocalUser({ payload, additionalFields, dbSchema }) { - try { - /** - * User auth - * - * @description Authenticate user - */ - - const { email, username, password } = payload; - - const dbFullName = process.env.DSQL_DB_NAME || ""; - const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; - const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - - /** - * Check input validity - * - * @description Check input validity - */ - if (email?.match(/ /) || username?.match(/ /) || password?.match(/ /)) { - return { - success: false, - msg: "Invalid Email/Password format", - }; - } - - /** - * Password hash - * - * @description Password hash - */ - let hashedPassword = hashPassword({ - password: password, - encryptionKey: encryptionKey, - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - const tableSchema = dbSchema?.tables.find((tb) => tb?.tableName === "users"); - - let foundUser = await varDatabaseDbHandler({ - queryString: `SELECT * FROM users WHERE email = ? OR username = ?`, - queryValuesArray: [email || "", username || ""], - database: dbFullName.replace(/[^a-z0-9_]/g, ""), - tableSchema, - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - if (!foundUser || !foundUser[0]) - return { - success: false, - payload: null, - msg: "No user found", - }; - - let isPasswordCorrect = false; - - if (foundUser && foundUser[0]) { - isPasswordCorrect = hashedPassword === foundUser[0].password; - } - - let socialUserValid = false; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - if (!isPasswordCorrect && !socialUserValid) { - return { - success: false, - msg: "Wrong password, no social login validity", - payload: null, - }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - let csrfKey = Math.random().toString(36).substring(2) + "-" + Math.random().toString(36).substring(2); - - let userPayload = { - id: foundUser[0].id, - first_name: foundUser[0].first_name, - last_name: foundUser[0].last_name, - username: foundUser[0].username, - email: foundUser[0].email, - phone: foundUser[0].phone, - social_id: foundUser[0].social_id, - image: foundUser[0].image, - image_thumbnail: foundUser[0].image_thumbnail, - verification_status: foundUser[0].verification_status, - social_login: foundUser[0].social_login, - social_platform: foundUser[0].social_platform, - csrf_k: csrfKey, - more_data: foundUser[0].more_user_data, - logged_in_status: true, - date: Date.now(), - }; - - if (additionalFields && Array.isArray(additionalFields) && additionalFields.length > 0) { - additionalFields.forEach((key) => { - // @ts-ignore - userPayload[key] = foundUser?.[0][key]; - }); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** ********************* Send Response */ - return { - success: true, - msg: "Login Successful", - payload: userPayload, - userId: "0", - }; - - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("Error in local login-user Request =>", error.message); - return { - success: false, - msg: "Login Failed", - }; - } -} - -module.exports = loginLocalUser; +// @ts-check + +const hashPassword = require("../../functions/hashPassword"); +const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler"); + +/** + * + * @param {object} param0 + * @param {{ + * email?: string, + * username?: string, + * password: string, + * }} param0.payload + * @param {string[]} [param0.additionalFields] + * @param {import("../../types/database-schema.td").DSQL_DatabaseSchemaType} [param0.dbSchema] + * @returns + */ +async function loginLocalUser({ payload, additionalFields, dbSchema }) { + try { + /** + * User auth + * + * @description Authenticate user + */ + + const { email, username, password } = payload; + + const dbFullName = process.env.DSQL_DB_NAME || ""; + const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; + const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; + + /** + * Check input validity + * + * @description Check input validity + */ + if (email?.match(/ /) || username?.match(/ /) || password?.match(/ /)) { + return { + success: false, + msg: "Invalid Email/Password format", + }; + } + + /** + * Password hash + * + * @description Password hash + */ + let hashedPassword = hashPassword({ + password: password, + encryptionKey: encryptionKey, + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + const tableSchema = dbSchema?.tables.find((tb) => tb?.tableName === "users"); + + let foundUser = await varDatabaseDbHandler({ + queryString: `SELECT * FROM users WHERE email = ? OR username = ?`, + queryValuesArray: [email || "", username || ""], + database: dbFullName.replace(/[^a-z0-9_]/g, ""), + tableSchema, + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + if (!foundUser || !foundUser[0]) + return { + success: false, + payload: null, + msg: "No user found", + }; + + let isPasswordCorrect = false; + + if (foundUser && foundUser[0]) { + isPasswordCorrect = hashedPassword === foundUser[0].password; + } + + let socialUserValid = false; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + if (!isPasswordCorrect && !socialUserValid) { + return { + success: false, + msg: "Wrong password, no social login validity", + payload: null, + }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + let csrfKey = Math.random().toString(36).substring(2) + "-" + Math.random().toString(36).substring(2); + + let userPayload = { + id: foundUser[0].id, + first_name: foundUser[0].first_name, + last_name: foundUser[0].last_name, + username: foundUser[0].username, + email: foundUser[0].email, + phone: foundUser[0].phone, + social_id: foundUser[0].social_id, + image: foundUser[0].image, + image_thumbnail: foundUser[0].image_thumbnail, + verification_status: foundUser[0].verification_status, + social_login: foundUser[0].social_login, + social_platform: foundUser[0].social_platform, + csrf_k: csrfKey, + more_data: foundUser[0].more_user_data, + logged_in_status: true, + date: Date.now(), + }; + + if (additionalFields && Array.isArray(additionalFields) && additionalFields.length > 0) { + additionalFields.forEach((key) => { + // @ts-ignore + userPayload[key] = foundUser?.[0][key]; + }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** ********************* Send Response */ + return { + success: true, + msg: "Login Successful", + payload: userPayload, + userId: "0", + }; + + //////////////////////////////////////// + } catch (/** @type {*} */ error) { + console.log("Error in local login-user Request =>", error.message); + return { + success: false, + msg: "Login Failed", + }; + } +} + +module.exports = loginLocalUser; diff --git a/engine/user/reauth-user.js b/engine/user/reauth-user.js index 5b18578..bbc25fc 100644 --- a/engine/user/reauth-user.js +++ b/engine/user/reauth-user.js @@ -1,106 +1,106 @@ -// @ts-check - -const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler"); - -/** - * - * @param {object} param0 - * @param {*} param0.existingUser - * @param {string[]} [param0.additionalFields] - * @param {import("../../types/database-schema.td").DSQL_DatabaseSchemaType} [param0.dbSchema] - * @returns - */ -async function localReauthUser({ existingUser, additionalFields, dbSchema }) { - try { - /** - * Grab data - * - * @description Grab data - */ - const dbFullName = process.env.DSQL_DB_NAME || ""; - - /** - * GRAB user - * - * @description GRAB user - */ - const tableSchema = dbSchema?.tables.find((tb) => tb?.tableName === "users"); - - let foundUser = - existingUser?.id && existingUser.id.toString().match(/./) - ? await varDatabaseDbHandler({ - queryString: `SELECT * FROM users WHERE id=?`, - queryValuesArray: [existingUser.id], - database: dbFullName.replace(/[^a-z0-9_]/g, ""), - tableSchema, - }) - : null; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - if (!foundUser || !foundUser[0]) - return { - success: false, - payload: null, - msg: "No user found", - }; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - let csrfKey = Math.random().toString(36).substring(2) + "-" + Math.random().toString(36).substring(2); - - let userPayload = { - id: foundUser[0].id, - first_name: foundUser[0].first_name, - last_name: foundUser[0].last_name, - username: foundUser[0].username, - email: foundUser[0].email, - phone: foundUser[0].phone, - social_id: foundUser[0].social_id, - image: foundUser[0].image, - image_thumbnail: foundUser[0].image_thumbnail, - verification_status: foundUser[0].verification_status, - social_login: foundUser[0].social_login, - social_platform: foundUser[0].social_platform, - csrf_k: csrfKey, - more_data: foundUser[0].more_user_data, - logged_in_status: true, - date: Date.now(), - }; - - if (additionalFields && Array.isArray(additionalFields) && additionalFields.length > 0) { - additionalFields.forEach((key) => { - // @ts-ignore - userPayload[key] = foundUser?.[0][key]; - }); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** ********************* Send Response */ - return { - success: true, - msg: "Login Successful", - payload: userPayload, - userId: "0", - }; - - //////////////////////////////////////// - - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("Error in local login-user Request =>", error.message); - return { - success: false, - msg: "Login Failed", - }; - } -} - -module.exports = localReauthUser; +// @ts-check + +const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler"); + +/** + * + * @param {object} param0 + * @param {*} param0.existingUser + * @param {string[]} [param0.additionalFields] + * @param {import("../../types/database-schema.td").DSQL_DatabaseSchemaType} [param0.dbSchema] + * @returns + */ +async function localReauthUser({ existingUser, additionalFields, dbSchema }) { + try { + /** + * Grab data + * + * @description Grab data + */ + const dbFullName = process.env.DSQL_DB_NAME || ""; + + /** + * GRAB user + * + * @description GRAB user + */ + const tableSchema = dbSchema?.tables.find((tb) => tb?.tableName === "users"); + + let foundUser = + existingUser?.id && existingUser.id.toString().match(/./) + ? await varDatabaseDbHandler({ + queryString: `SELECT * FROM users WHERE id=?`, + queryValuesArray: [existingUser.id], + database: dbFullName.replace(/[^a-z0-9_]/g, ""), + tableSchema, + }) + : null; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + if (!foundUser || !foundUser[0]) + return { + success: false, + payload: null, + msg: "No user found", + }; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + let csrfKey = Math.random().toString(36).substring(2) + "-" + Math.random().toString(36).substring(2); + + let userPayload = { + id: foundUser[0].id, + first_name: foundUser[0].first_name, + last_name: foundUser[0].last_name, + username: foundUser[0].username, + email: foundUser[0].email, + phone: foundUser[0].phone, + social_id: foundUser[0].social_id, + image: foundUser[0].image, + image_thumbnail: foundUser[0].image_thumbnail, + verification_status: foundUser[0].verification_status, + social_login: foundUser[0].social_login, + social_platform: foundUser[0].social_platform, + csrf_k: csrfKey, + more_data: foundUser[0].more_user_data, + logged_in_status: true, + date: Date.now(), + }; + + if (additionalFields && Array.isArray(additionalFields) && additionalFields.length > 0) { + additionalFields.forEach((key) => { + // @ts-ignore + userPayload[key] = foundUser?.[0][key]; + }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** ********************* Send Response */ + return { + success: true, + msg: "Login Successful", + payload: userPayload, + userId: "0", + }; + + //////////////////////////////////////// + + //////////////////////////////////////// + } catch (/** @type {*} */ error) { + console.log("Error in local login-user Request =>", error.message); + return { + success: false, + msg: "Login Failed", + }; + } +} + +module.exports = localReauthUser; diff --git a/engine/user/social/github-auth.js b/engine/user/social/github-auth.js index 11e48ea..e9f76ef 100644 --- a/engine/user/social/github-auth.js +++ b/engine/user/social/github-auth.js @@ -1,134 +1,134 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const http = require("http"); -const https = require("https"); -const encrypt = require("../../../functions/encrypt"); -const camelJoinedtoCamelSpace = require("../../engine/utils/camelJoinedtoCamelSpace"); -const githubLogin = require("./utils/githubLogin"); -const handleSocialDb = require("./utils/handleSocialDb"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -const database = process.env.DSQL_DB_NAME || ""; -const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; -const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - -/** - * SERVER FUNCTION: Login with google Function - * ============================================================================== - * - * @async - * - * @param {object} params - main params object - * @param {http.ServerResponse} params.res - HTTPS response object - * @param {string} params.code - * @param {string} [params.email] - * @param {string} params.clientId - * @param {string} params.clientSecret - * @param {object} [params.additionalFields] - * @param {import("../../../types/database-schema.td").DSQL_DatabaseSchemaType} params.dbSchema - */ -async function localGithubAuth({ res, code, email, clientId, clientSecret, additionalFields, dbSchema }) { - try { - /** - * User auth - * - * @description Authenticate user - */ - if (!code || !clientId || !clientSecret) { - return { - success: false, - msg: "Missing query params", - }; - } - - if (typeof code !== "string" || typeof clientId !== "string" || typeof clientSecret !== "string" || typeof database !== "string") { - return { - success: false, - msg: "Wrong Parameters", - }; - } - - /** - * Create new user folder and file - * - * @description Create new user folder and file - */ - const gitHubUser = await githubLogin({ - code: code, - clientId: clientId, - clientSecret: clientSecret, - }); - - if (!gitHubUser) { - return { - success: false, - msg: "No github user returned", - }; - } - - const targetDbName = database; - - const socialId = gitHubUser.name || gitHubUser.id || gitHubUser.login; - const targetName = gitHubUser.name || gitHubUser.login; - const nameArray = targetName?.match(/ /) ? targetName?.split(" ") : targetName?.match(/\-/) ? targetName?.split("-") : [targetName]; - - const payload = { - email: gitHubUser.email, - first_name: camelJoinedtoCamelSpace(nameArray[0]) || "", - last_name: camelJoinedtoCamelSpace(nameArray[1]) || "", - social_id: socialId, - social_platform: "github", - image: gitHubUser.avatar_url, - image_thumbnail: gitHubUser.avatar_url, - username: "github-user-" + socialId, - }; - - if (additionalFields && Object.keys(additionalFields).length > 0) { - Object.keys(additionalFields).forEach((key) => { - // @ts-ignore - payload[key] = additionalFields[key]; - }); - } - - const loggedInGithubUser = await handleSocialDb({ - database: targetDbName, - email: gitHubUser.email, - payload: payload, - social_platform: "github", - res: res, - social_id: socialId, - supEmail: email, - additionalFields, - dbSchema: dbSchema, - }); - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - return { ...loggedInGithubUser, dsqlUserId: "0" }; - - //////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("localGithubAuth error", error.message); - - return { success: false, msg: "Failed!" }; - } -} - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -module.exports = localGithubAuth; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const http = require("http"); +const https = require("https"); +const encrypt = require("../../../functions/encrypt"); +const camelJoinedtoCamelSpace = require("../../engine/utils/camelJoinedtoCamelSpace"); +const githubLogin = require("./utils/githubLogin"); +const handleSocialDb = require("./utils/handleSocialDb"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +const database = process.env.DSQL_DB_NAME || ""; +const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; +const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; + +/** + * SERVER FUNCTION: Login with google Function + * ============================================================================== + * + * @async + * + * @param {object} params - main params object + * @param {http.ServerResponse} params.res - HTTPS response object + * @param {string} params.code + * @param {string} [params.email] + * @param {string} params.clientId + * @param {string} params.clientSecret + * @param {object} [params.additionalFields] + * @param {import("../../../types/database-schema.td").DSQL_DatabaseSchemaType} params.dbSchema + */ +async function localGithubAuth({ res, code, email, clientId, clientSecret, additionalFields, dbSchema }) { + try { + /** + * User auth + * + * @description Authenticate user + */ + if (!code || !clientId || !clientSecret) { + return { + success: false, + msg: "Missing query params", + }; + } + + if (typeof code !== "string" || typeof clientId !== "string" || typeof clientSecret !== "string" || typeof database !== "string") { + return { + success: false, + msg: "Wrong Parameters", + }; + } + + /** + * Create new user folder and file + * + * @description Create new user folder and file + */ + const gitHubUser = await githubLogin({ + code: code, + clientId: clientId, + clientSecret: clientSecret, + }); + + if (!gitHubUser) { + return { + success: false, + msg: "No github user returned", + }; + } + + const targetDbName = database; + + const socialId = gitHubUser.name || gitHubUser.id || gitHubUser.login; + const targetName = gitHubUser.name || gitHubUser.login; + const nameArray = targetName?.match(/ /) ? targetName?.split(" ") : targetName?.match(/\-/) ? targetName?.split("-") : [targetName]; + + const payload = { + email: gitHubUser.email, + first_name: camelJoinedtoCamelSpace(nameArray[0]) || "", + last_name: camelJoinedtoCamelSpace(nameArray[1]) || "", + social_id: socialId, + social_platform: "github", + image: gitHubUser.avatar_url, + image_thumbnail: gitHubUser.avatar_url, + username: "github-user-" + socialId, + }; + + if (additionalFields && Object.keys(additionalFields).length > 0) { + Object.keys(additionalFields).forEach((key) => { + // @ts-ignore + payload[key] = additionalFields[key]; + }); + } + + const loggedInGithubUser = await handleSocialDb({ + database: targetDbName, + email: gitHubUser.email, + payload: payload, + social_platform: "github", + res: res, + social_id: socialId, + supEmail: email, + additionalFields, + dbSchema: dbSchema, + }); + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + return { ...loggedInGithubUser, dsqlUserId: "0" }; + + //////////////////////////////////////// + } catch (/** @type {*} */ error) { + console.log("localGithubAuth error", error.message); + + return { success: false, msg: "Failed!" }; + } +} + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +module.exports = localGithubAuth; diff --git a/engine/user/social/google-auth.js b/engine/user/social/google-auth.js index bb4ab15..7027901 100644 --- a/engine/user/social/google-auth.js +++ b/engine/user/social/google-auth.js @@ -1,169 +1,169 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const http = require("http"); -const https = require("https"); -const fs = require("fs"); -const path = require("path"); -const encrypt = require("../../../functions/encrypt"); -const decrypt = require("../../../functions/decrypt"); -const handleSocialDb = require("./utils/handleSocialDb"); -const httpsRequest = require("./utils/httpsRequest"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {object | null} FunctionReturn - * @property {boolean} success - Did the function run successfully? - * @property {import("../../types/user.td").DATASQUIREL_LoggedInUser | null} user - Returned User - * @property {number} [dsqlUserId] - Dsql User Id - * @property {string} [msg] - Response message - */ - -const database = process.env.DSQL_DB_NAME || ""; -const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; -const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - -/** - * SERVER FUNCTION: Login with google Function - * ============================================================================== - * - * @async - * - * @param {object} params - main params object - * @param {string} params.token - Google access token gotten from the client side - * @param {string} params.clientId - Google client id - * @param {http.ServerResponse} params.response - HTTPS response object - * @param {object} [params.additionalFields] - Additional Fields to be added to the user object - * @param {import("../../../types/database-schema.td").DSQL_DatabaseSchemaType} [params.dbSchema] - Database Schema - * - * @returns { Promise } - */ -async function localGoogleAuth({ dbSchema, token, clientId, response, additionalFields }) { - /** - * Send Response - * - * @description Send a boolean response - */ - try { - /** - * Grab User data - * - * @description Grab User data - * @type {{ success: boolean, payload: any, msg: string }} - */ - const payloadResponse = await httpsRequest({ - method: "POST", - hostname: "datasquirel.com", - path: "/user/grab-google-user-from-token", - body: { - token: token, - clientId: clientId, - }, - headers: { - Authorization: process.env.DSQL_API_KEY, - }, - }); - - const payload = payloadResponse.payload; - - if (!payloadResponse.success || !payload) { - console.log("payloadResponse Failed =>", payloadResponse); - return { - success: false, - msg: "User fetch Error", - }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - if (!database || typeof database != "string" || database?.match(/ /)) { - return { - success: false, - user: undefined, - msg: "Please provide a database slug(database name in lowercase with no spaces)", - }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Create new user folder and file - * - * @description Create new user folder and file - */ - const targetDbName = database; - - if (!payload) { - return { - success: false, - msg: "No payload", - }; - } - - const { given_name, family_name, email, sub, picture, email_verified } = payload; - - const payloadObject = { - email: email || "", - first_name: given_name || "", - last_name: family_name || "", - social_id: sub, - social_platform: "google", - image: picture || "", - image_thumbnail: picture || "", - username: `google-user-${sub}`, - }; - - if (additionalFields && Object.keys(additionalFields).length > 0) { - Object.keys(additionalFields).forEach((key) => { - // @ts-ignore - payloadObject[key] = additionalFields[key]; - }); - } - - const loggedInGoogleUser = await handleSocialDb({ - database: targetDbName, - email: email || "", - payload: payloadObject, - social_platform: "google", - res: response, - social_id: sub, - additionalFields, - dbSchema, - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - return { ...loggedInGoogleUser, dsqlUserId: "0" }; - - //////////////////////////////////////// - } catch (error) { - return { - success: false, - msg: "User fetch Error", - }; - - //////////////////////////////////////// - } -} - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -module.exports = localGoogleAuth; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const http = require("http"); +const https = require("https"); +const fs = require("fs"); +const path = require("path"); +const encrypt = require("../../../functions/encrypt"); +const decrypt = require("../../../functions/decrypt"); +const handleSocialDb = require("./utils/handleSocialDb"); +const httpsRequest = require("./utils/httpsRequest"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {object | null} FunctionReturn + * @property {boolean} success - Did the function run successfully? + * @property {import("../../types/user.td").DATASQUIREL_LoggedInUser | null} user - Returned User + * @property {number} [dsqlUserId] - Dsql User Id + * @property {string} [msg] - Response message + */ + +const database = process.env.DSQL_DB_NAME || ""; +const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; +const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; + +/** + * SERVER FUNCTION: Login with google Function + * ============================================================================== + * + * @async + * + * @param {object} params - main params object + * @param {string} params.token - Google access token gotten from the client side + * @param {string} params.clientId - Google client id + * @param {http.ServerResponse} params.response - HTTPS response object + * @param {object} [params.additionalFields] - Additional Fields to be added to the user object + * @param {import("../../../types/database-schema.td").DSQL_DatabaseSchemaType} [params.dbSchema] - Database Schema + * + * @returns { Promise } + */ +async function localGoogleAuth({ dbSchema, token, clientId, response, additionalFields }) { + /** + * Send Response + * + * @description Send a boolean response + */ + try { + /** + * Grab User data + * + * @description Grab User data + * @type {{ success: boolean, payload: any, msg: string }} + */ + const payloadResponse = await httpsRequest({ + method: "POST", + hostname: "datasquirel.com", + path: "/user/grab-google-user-from-token", + body: { + token: token, + clientId: clientId, + }, + headers: { + Authorization: process.env.DSQL_API_KEY, + }, + }); + + const payload = payloadResponse.payload; + + if (!payloadResponse.success || !payload) { + console.log("payloadResponse Failed =>", payloadResponse); + return { + success: false, + msg: "User fetch Error", + }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + if (!database || typeof database != "string" || database?.match(/ /)) { + return { + success: false, + user: undefined, + msg: "Please provide a database slug(database name in lowercase with no spaces)", + }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Create new user folder and file + * + * @description Create new user folder and file + */ + const targetDbName = database; + + if (!payload) { + return { + success: false, + msg: "No payload", + }; + } + + const { given_name, family_name, email, sub, picture, email_verified } = payload; + + const payloadObject = { + email: email || "", + first_name: given_name || "", + last_name: family_name || "", + social_id: sub, + social_platform: "google", + image: picture || "", + image_thumbnail: picture || "", + username: `google-user-${sub}`, + }; + + if (additionalFields && Object.keys(additionalFields).length > 0) { + Object.keys(additionalFields).forEach((key) => { + // @ts-ignore + payloadObject[key] = additionalFields[key]; + }); + } + + const loggedInGoogleUser = await handleSocialDb({ + database: targetDbName, + email: email || "", + payload: payloadObject, + social_platform: "google", + res: response, + social_id: sub, + additionalFields, + dbSchema, + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + return { ...loggedInGoogleUser, dsqlUserId: "0" }; + + //////////////////////////////////////// + } catch (error) { + return { + success: false, + msg: "User fetch Error", + }; + + //////////////////////////////////////// + } +} + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +module.exports = localGoogleAuth; diff --git a/engine/user/social/utils/githubLogin.js b/engine/user/social/utils/githubLogin.js index 6ef06b2..c7e6f1b 100644 --- a/engine/user/social/utils/githubLogin.js +++ b/engine/user/social/utils/githubLogin.js @@ -1,164 +1,164 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const fs = require("fs"); -const httpsRequest = require("./httpsRequest"); -const dbHandler = require("../../../engine/utils/dbHandler"); - -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// - -/** - * - * @typedef {object} GithubUserPayload - * @property {string} login - Full name merged eg. "JohnDoe" - * @property {number} id - github user id - * @property {string} node_id - Some other id - * @property {string} avatar_url - profile picture - * @property {string} gravatar_id - some other id - * @property {string} url - Github user URL - * @property {string} html_url - User html URL - whatever that means - * @property {string} followers_url - Followers URL - * @property {string} following_url - Following URL - * @property {string} gists_url - Gists URL - * @property {string} starred_url - Starred URL - * @property {string} subscriptions_url - Subscriptions URL - * @property {string} organizations_url - Organizations URL - * @property {string} repos_url - Repositories URL - * @property {string} received_events_url - Received Events URL - * @property {string} type - Common value => "User" - * @property {boolean} site_admin - Is site admin or not? Boolean - * @property {string} name - More like "username" - * @property {string} company - User company - * @property {string} blog - User blog URL - * @property {string} location - User Location - * @property {string} email - User Email - * @property {string} hireable - Is user hireable - * @property {string} bio - User bio - * @property {string} twitter_username - User twitter username - * @property {number} public_repos - Number of public repositories - * @property {number} public_gists - Number of public gists - * @property {number} followers - Number of followers - * @property {number} following - Number of following - * @property {string} created_at - Date created - * @property {string} updated_at - Date updated - */ - -/** - * Login/signup a github user - * ============================================================================== - * @async - * - * @param {Object} params - foundUser if any - * @param {string} params.code - github auth token - * @param {string} params.clientId - github client Id - * @param {string} params.clientSecret - github client Secret - * - * @returns {Promise} - */ -async function githubLogin({ code, clientId, clientSecret }) { - /** @type {GithubUserPayload | null} */ - let gitHubUser = null; - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - try { - /** - * Create new user folder and file - * - * @description Create new user folder and file - */ - // const response = await fetch(`https://github.com/login/oauth/access_token?client_id=${process.env.GITHUB_ID}`); - const response = await httpsRequest({ - method: "POST", - hostname: "github.com", - path: `/login/oauth/access_token?client_id=${clientId}&client_secret=${clientSecret}&code=${code}`, - headers: { - Accept: "application/json", - "User-Agent": "*", - }, - }); - - // `https://github.com/login/oauth/access_token?client_id=${process.env.GITHUB_ID}&client_secret=${process.env.GITHUB_SECRET}&code=${code}`, - // body: JSON.stringify({ - // client_id: process.env.GITHUB_ID, - // client_secret: process.env.GITHUB_SECRET, - // code: code, - // }), - - const accessTokenObject = JSON.parse(response); - - if (!accessTokenObject?.access_token) { - return gitHubUser; - } - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - const userDataResponse = await httpsRequest({ - method: "GET", - hostname: "api.github.com", - path: "/user", - headers: { - Authorization: `Bearer ${accessTokenObject.access_token}`, - "User-Agent": "*", - }, - }); - - gitHubUser = JSON.parse(userDataResponse); - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - if (!gitHubUser?.email) { - const existingGithubUser = await dbHandler({ - query: `SELECT email FROM users WHERE social_login='1' AND social_platform='github' AND social_id= ?`, - values: [gitHubUser?.id || ""], - }); - - if (existingGithubUser && existingGithubUser[0] && gitHubUser) { - gitHubUser.email = existingGithubUser[0].email; - } - } - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - } catch (/** @type {*} */ error) { - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - console.log("ERROR in githubLogin.js backend function =>", error.message); - - // serverError({ - // component: "/api/social-login/github-auth/catch-error", - // message: error.message, - // user: user, - // }); - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - } - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - return gitHubUser; -} - -module.exports = githubLogin; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const fs = require("fs"); +const httpsRequest = require("./httpsRequest"); +const dbHandler = require("../../../engine/utils/dbHandler"); + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +/** + * + * @typedef {object} GithubUserPayload + * @property {string} login - Full name merged eg. "JohnDoe" + * @property {number} id - github user id + * @property {string} node_id - Some other id + * @property {string} avatar_url - profile picture + * @property {string} gravatar_id - some other id + * @property {string} url - Github user URL + * @property {string} html_url - User html URL - whatever that means + * @property {string} followers_url - Followers URL + * @property {string} following_url - Following URL + * @property {string} gists_url - Gists URL + * @property {string} starred_url - Starred URL + * @property {string} subscriptions_url - Subscriptions URL + * @property {string} organizations_url - Organizations URL + * @property {string} repos_url - Repositories URL + * @property {string} received_events_url - Received Events URL + * @property {string} type - Common value => "User" + * @property {boolean} site_admin - Is site admin or not? Boolean + * @property {string} name - More like "username" + * @property {string} company - User company + * @property {string} blog - User blog URL + * @property {string} location - User Location + * @property {string} email - User Email + * @property {string} hireable - Is user hireable + * @property {string} bio - User bio + * @property {string} twitter_username - User twitter username + * @property {number} public_repos - Number of public repositories + * @property {number} public_gists - Number of public gists + * @property {number} followers - Number of followers + * @property {number} following - Number of following + * @property {string} created_at - Date created + * @property {string} updated_at - Date updated + */ + +/** + * Login/signup a github user + * ============================================================================== + * @async + * + * @param {Object} params - foundUser if any + * @param {string} params.code - github auth token + * @param {string} params.clientId - github client Id + * @param {string} params.clientSecret - github client Secret + * + * @returns {Promise} + */ +async function githubLogin({ code, clientId, clientSecret }) { + /** @type {GithubUserPayload | null} */ + let gitHubUser = null; + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + try { + /** + * Create new user folder and file + * + * @description Create new user folder and file + */ + // const response = await fetch(`https://github.com/login/oauth/access_token?client_id=${process.env.GITHUB_ID}`); + const response = await httpsRequest({ + method: "POST", + hostname: "github.com", + path: `/login/oauth/access_token?client_id=${clientId}&client_secret=${clientSecret}&code=${code}`, + headers: { + Accept: "application/json", + "User-Agent": "*", + }, + }); + + // `https://github.com/login/oauth/access_token?client_id=${process.env.GITHUB_ID}&client_secret=${process.env.GITHUB_SECRET}&code=${code}`, + // body: JSON.stringify({ + // client_id: process.env.GITHUB_ID, + // client_secret: process.env.GITHUB_SECRET, + // code: code, + // }), + + const accessTokenObject = JSON.parse(response); + + if (!accessTokenObject?.access_token) { + return gitHubUser; + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + const userDataResponse = await httpsRequest({ + method: "GET", + hostname: "api.github.com", + path: "/user", + headers: { + Authorization: `Bearer ${accessTokenObject.access_token}`, + "User-Agent": "*", + }, + }); + + gitHubUser = JSON.parse(userDataResponse); + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + if (!gitHubUser?.email) { + const existingGithubUser = await dbHandler({ + query: `SELECT email FROM users WHERE social_login='1' AND social_platform='github' AND social_id= ?`, + values: [gitHubUser?.id || ""], + }); + + if (existingGithubUser && existingGithubUser[0] && gitHubUser) { + gitHubUser.email = existingGithubUser[0].email; + } + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + } catch (/** @type {*} */ error) { + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + console.log("ERROR in githubLogin.js backend function =>", error.message); + + // serverError({ + // component: "/api/social-login/github-auth/catch-error", + // message: error.message, + // user: user, + // }); + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + return gitHubUser; +} + +module.exports = githubLogin; diff --git a/engine/user/social/utils/handleSocialDb.js b/engine/user/social/utils/handleSocialDb.js index 1d1b3b6..ff4021b 100644 --- a/engine/user/social/utils/handleSocialDb.js +++ b/engine/user/social/utils/handleSocialDb.js @@ -1,376 +1,376 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const fs = require("fs"); -const http = require("http"); -const varDatabaseDbHandler = require("../../../engine/utils/varDatabaseDbHandler"); -const addDbEntry = require("../../../query/utils/addDbEntry"); -const encrypt = require("../../../../functions/encrypt"); - -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// - -/** - * @typedef {object} FunctionReturn - * @property {boolean} success - Did the operation complete successfully or not? - * @property {{ - * id: number, - * first_name: string, - * last_name: string, - * }|null} user - User payload object: or "null" - * @property {string} [msg] - Message - * @property {string} [error] - Error Message - * @property {string | number} [social_id] - Social Id - * @property {string} [social_platform] - Social Platform - * @property {object} [payload] - Payload - * @property {boolean} [alert] - Alert - * @property {*} [newUser] - New User - */ - -//////////////////////////////////////////////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - -const database = process.env.DSQL_DB_NAME || ""; -const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; -const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - -//////////////////////////////////////////////// -//////////////////////////////////////////////// -//////////////////////////////////////////////// - -/** - * Handle Social User Auth on Datasquirel Database - * ============================================================================== - * - * @description This function handles all social login logic after the social user - * has been authenticated and userpayload is present. The payload MUST contain the - * specified fields because this funciton will create a new user if the authenticated - * user does not exist. - * - * @param {{ - * database: string|null|undefined, - * social_id: string|number, - * email: string, - * social_platform: string, - * payload: { - * social_id: string | number, - * email: string, - * social_platform: string, - * first_name: string, - * last_name: string, - * image: string, - * image_thumbnail: string, - * username: string, - * }, - * res: http.ServerResponse, - * supEmail?: string | null, - * additionalFields?: object, - * dbSchema: import("../../../../types/database-schema.td").DSQL_DatabaseSchemaType | undefined - * }} params - function parameters inside an object - * - * @returns {Promise} - Response object - */ -async function handleSocialDb({ social_id, email, social_platform, payload, res, supEmail, additionalFields, dbSchema }) { - const tableSchema = dbSchema?.tables.find((tb) => tb?.tableName === "users"); - - try { - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - let existingSocialIdUser = await varDatabaseDbHandler({ - database: database ? database : "datasquirel", - queryString: `SELECT * FROM users WHERE social_id = ? AND social_login='1' AND social_platform = ? `, - queryValuesArray: [social_id.toString(), social_platform], - }); - - if (existingSocialIdUser && existingSocialIdUser[0]) { - return await loginSocialUser({ - user: existingSocialIdUser[0], - social_platform, - res, - database, - additionalFields, - }); - } - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - const finalEmail = email ? email : supEmail ? supEmail : null; - - if (!finalEmail) { - return { - success: false, - user: null, - msg: "No Email Present", - social_id, - social_platform, - payload, - }; - } - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - let existingEmailOnly = await varDatabaseDbHandler({ - database: database ? database : "datasquirel", - queryString: `SELECT * FROM users WHERE email = ?`, - queryValuesArray: [finalEmail], - tableSchema, - }); - - if (existingEmailOnly && existingEmailOnly[0]) { - return { - success: false, - user: null, - msg: "This Email is already taken", - alert: true, - }; - } - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - const foundUser = await varDatabaseDbHandler({ - database: database ? database : "datasquirel", - queryString: `SELECT * FROM users WHERE email='${finalEmail}' AND social_login='1' AND social_platform='${social_platform}' AND social_id='${social_id}'`, - }); - - if (foundUser && foundUser[0]) { - return await loginSocialUser({ - user: payload, - social_platform, - res, - database, - additionalFields, - }); - } - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - const socialHashedPassword = encrypt({ - data: social_id.toString(), - encryptionKey, - encryptionSalt, - }); - - const data = { - social_login: "1", - verification_status: supEmail ? "0" : "1", - password: socialHashedPassword, - }; - - Object.keys(payload).forEach((key) => { - // @ts-ignore - data[key] = payload[key]; - }); - - const newUser = await addDbEntry({ - dbFullName: database ? database : "datasquirel", - tableName: "users", - duplicateColumnName: "email", - duplicateColumnValue: finalEmail, - data: { - ...data, - email: finalEmail, - }, - encryptionKey, - encryptionSalt, - tableSchema, - }); - - if (newUser?.insertId) { - const newUserQueried = await varDatabaseDbHandler({ - database: database ? database : "datasquirel", - queryString: `SELECT * FROM users WHERE id='${newUser.insertId}'`, - }); - - if (!newUserQueried || !newUserQueried[0]) - return { - success: false, - user: null, - msg: "User Insertion Failed!", - }; - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - if (supEmail && database?.match(/^datasquirel$/)) { - /** - * Send email Verification - * - * @description Send verification email to newly created agent - */ - let generatedToken = encrypt({ - data: JSON.stringify({ - id: newUser.insertId, - email: supEmail, - dateCode: Date.now(), - }), - encryptionKey, - encryptionSalt, - }); - } - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - return await loginSocialUser({ - user: newUserQueried[0], - social_platform, - res, - database, - additionalFields, - }); - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - } else { - console.log("Social User Failed to insert in 'handleSocialDb.js' backend function =>", newUser); - - return { - success: false, - user: null, - msg: "Social User Failed to insert in 'handleSocialDb.js' backend function => ", - newUser: newUser, - }; - } - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - } catch (/** @type {*} */ error) { - console.log("ERROR in 'handleSocialDb.js' backend function =>", error.message); - - return { - success: false, - user: null, - error: error.message, - }; - - // serverError({ - // component: "/functions/backend/social-login/handleSocialDb.js - main-catch-error", - // message: error.message, - // user: { first_name, last_name }, - // }); - } - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// -} - -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// - -/** - * Function to login social user - * ============================================================================== - * @description This function logs in the user after 'handleSocialDb' function finishes - * the user creation or confirmation process - * - * @async - * - * @param {object} params - function parameters inside an object - * @param {{ - * first_name: string, - * last_name: string, - * email: string, - * social_id: string|number, - * }} params.user - user object - * @param {string} params.social_platform - Whether its "google" or "facebook" or "github" - * @param {http.ServerResponse} params.res - Https response object - * @param {string|null} params.database - Target Database - * @param {object} [params.additionalFields] - Additional fields to be added to the user payload - * - * @returns {Promise<{ - * success: boolean, - * user: { id: number, first_name: string, last_name: string } | null - * msg?: string - * }>} - */ -async function loginSocialUser({ user, social_platform, res, database, additionalFields }) { - const foundUser = await varDatabaseDbHandler({ - database: database ? database : "datasquirel", - queryString: `SELECT * FROM users WHERE email='${user.email}' AND social_id='${user.social_id}' AND social_platform='${social_platform}'`, - }); - - let csrfKey = Math.random().toString(36).substring(2) + "-" + Math.random().toString(36).substring(2); - - if (!foundUser?.[0]) { - return { - success: false, - user: null, - msg: "User Not Found", - }; - } - - let userPayload = { - id: foundUser[0].id, - type: foundUser[0].type || "", - stripe_id: foundUser[0].stripe_id || "", - first_name: foundUser[0].first_name, - last_name: foundUser[0].last_name, - username: foundUser[0].username, - email: foundUser[0].email, - social_id: foundUser[0].social_id, - image: foundUser[0].image, - image_thumbnail: foundUser[0].image_thumbnail, - verification_status: foundUser[0].verification_status, - social_login: foundUser[0].social_login, - social_platform: foundUser[0].social_platform, - csrf_k: csrfKey, - logged_in_status: true, - date: Date.now(), - }; - - if (additionalFields && Object.keys(additionalFields).length > 0) { - Object.keys(additionalFields).forEach((key) => { - // @ts-ignore - userPayload[key] = foundUser[0][key]; - }); - } - - let encryptedPayload = encrypt({ - data: JSON.stringify(userPayload), - encryptionKey, - encryptionSalt, - }); - - if (res?.setHeader) { - res.setHeader("Set-Cookie", [`datasquirelAuthKey=${encryptedPayload};samesite=strict;path=/;HttpOnly=true;Secure=true`, `csrf=${csrfKey};samesite=strict;path=/;HttpOnly=true`]); - } - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - return { - success: true, - user: userPayload, - }; -} - -module.exports = handleSocialDb; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const fs = require("fs"); +const http = require("http"); +const varDatabaseDbHandler = require("../../../engine/utils/varDatabaseDbHandler"); +const addDbEntry = require("../../../query/utils/addDbEntry"); +const encrypt = require("../../../../functions/encrypt"); + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +/** + * @typedef {object} FunctionReturn + * @property {boolean} success - Did the operation complete successfully or not? + * @property {{ + * id: number, + * first_name: string, + * last_name: string, + * }|null} user - User payload object: or "null" + * @property {string} [msg] - Message + * @property {string} [error] - Error Message + * @property {string | number} [social_id] - Social Id + * @property {string} [social_platform] - Social Platform + * @property {object} [payload] - Payload + * @property {boolean} [alert] - Alert + * @property {*} [newUser] - New User + */ + +//////////////////////////////////////////////// +//////////////////////////////////////////////// +//////////////////////////////////////////////// + +const database = process.env.DSQL_DB_NAME || ""; +const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; +const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; + +//////////////////////////////////////////////// +//////////////////////////////////////////////// +//////////////////////////////////////////////// + +/** + * Handle Social User Auth on Datasquirel Database + * ============================================================================== + * + * @description This function handles all social login logic after the social user + * has been authenticated and userpayload is present. The payload MUST contain the + * specified fields because this funciton will create a new user if the authenticated + * user does not exist. + * + * @param {{ + * database: string|null|undefined, + * social_id: string|number, + * email: string, + * social_platform: string, + * payload: { + * social_id: string | number, + * email: string, + * social_platform: string, + * first_name: string, + * last_name: string, + * image: string, + * image_thumbnail: string, + * username: string, + * }, + * res: http.ServerResponse, + * supEmail?: string | null, + * additionalFields?: object, + * dbSchema: import("../../../../types/database-schema.td").DSQL_DatabaseSchemaType | undefined + * }} params - function parameters inside an object + * + * @returns {Promise} - Response object + */ +async function handleSocialDb({ social_id, email, social_platform, payload, res, supEmail, additionalFields, dbSchema }) { + const tableSchema = dbSchema?.tables.find((tb) => tb?.tableName === "users"); + + try { + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + let existingSocialIdUser = await varDatabaseDbHandler({ + database: database ? database : "datasquirel", + queryString: `SELECT * FROM users WHERE social_id = ? AND social_login='1' AND social_platform = ? `, + queryValuesArray: [social_id.toString(), social_platform], + }); + + if (existingSocialIdUser && existingSocialIdUser[0]) { + return await loginSocialUser({ + user: existingSocialIdUser[0], + social_platform, + res, + database, + additionalFields, + }); + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + const finalEmail = email ? email : supEmail ? supEmail : null; + + if (!finalEmail) { + return { + success: false, + user: null, + msg: "No Email Present", + social_id, + social_platform, + payload, + }; + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + let existingEmailOnly = await varDatabaseDbHandler({ + database: database ? database : "datasquirel", + queryString: `SELECT * FROM users WHERE email = ?`, + queryValuesArray: [finalEmail], + tableSchema, + }); + + if (existingEmailOnly && existingEmailOnly[0]) { + return { + success: false, + user: null, + msg: "This Email is already taken", + alert: true, + }; + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + const foundUser = await varDatabaseDbHandler({ + database: database ? database : "datasquirel", + queryString: `SELECT * FROM users WHERE email='${finalEmail}' AND social_login='1' AND social_platform='${social_platform}' AND social_id='${social_id}'`, + }); + + if (foundUser && foundUser[0]) { + return await loginSocialUser({ + user: payload, + social_platform, + res, + database, + additionalFields, + }); + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + const socialHashedPassword = encrypt({ + data: social_id.toString(), + encryptionKey, + encryptionSalt, + }); + + const data = { + social_login: "1", + verification_status: supEmail ? "0" : "1", + password: socialHashedPassword, + }; + + Object.keys(payload).forEach((key) => { + // @ts-ignore + data[key] = payload[key]; + }); + + const newUser = await addDbEntry({ + dbFullName: database ? database : "datasquirel", + tableName: "users", + duplicateColumnName: "email", + duplicateColumnValue: finalEmail, + data: { + ...data, + email: finalEmail, + }, + encryptionKey, + encryptionSalt, + tableSchema, + }); + + if (newUser?.insertId) { + const newUserQueried = await varDatabaseDbHandler({ + database: database ? database : "datasquirel", + queryString: `SELECT * FROM users WHERE id='${newUser.insertId}'`, + }); + + if (!newUserQueried || !newUserQueried[0]) + return { + success: false, + user: null, + msg: "User Insertion Failed!", + }; + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + if (supEmail && database?.match(/^datasquirel$/)) { + /** + * Send email Verification + * + * @description Send verification email to newly created agent + */ + let generatedToken = encrypt({ + data: JSON.stringify({ + id: newUser.insertId, + email: supEmail, + dateCode: Date.now(), + }), + encryptionKey, + encryptionSalt, + }); + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + return await loginSocialUser({ + user: newUserQueried[0], + social_platform, + res, + database, + additionalFields, + }); + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + } else { + console.log("Social User Failed to insert in 'handleSocialDb.js' backend function =>", newUser); + + return { + success: false, + user: null, + msg: "Social User Failed to insert in 'handleSocialDb.js' backend function => ", + newUser: newUser, + }; + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + } catch (/** @type {*} */ error) { + console.log("ERROR in 'handleSocialDb.js' backend function =>", error.message); + + return { + success: false, + user: null, + error: error.message, + }; + + // serverError({ + // component: "/functions/backend/social-login/handleSocialDb.js - main-catch-error", + // message: error.message, + // user: { first_name, last_name }, + // }); + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +/** + * Function to login social user + * ============================================================================== + * @description This function logs in the user after 'handleSocialDb' function finishes + * the user creation or confirmation process + * + * @async + * + * @param {object} params - function parameters inside an object + * @param {{ + * first_name: string, + * last_name: string, + * email: string, + * social_id: string|number, + * }} params.user - user object + * @param {string} params.social_platform - Whether its "google" or "facebook" or "github" + * @param {http.ServerResponse} params.res - Https response object + * @param {string|null} params.database - Target Database + * @param {object} [params.additionalFields] - Additional fields to be added to the user payload + * + * @returns {Promise<{ + * success: boolean, + * user: { id: number, first_name: string, last_name: string } | null + * msg?: string + * }>} + */ +async function loginSocialUser({ user, social_platform, res, database, additionalFields }) { + const foundUser = await varDatabaseDbHandler({ + database: database ? database : "datasquirel", + queryString: `SELECT * FROM users WHERE email='${user.email}' AND social_id='${user.social_id}' AND social_platform='${social_platform}'`, + }); + + let csrfKey = Math.random().toString(36).substring(2) + "-" + Math.random().toString(36).substring(2); + + if (!foundUser?.[0]) { + return { + success: false, + user: null, + msg: "User Not Found", + }; + } + + let userPayload = { + id: foundUser[0].id, + type: foundUser[0].type || "", + stripe_id: foundUser[0].stripe_id || "", + first_name: foundUser[0].first_name, + last_name: foundUser[0].last_name, + username: foundUser[0].username, + email: foundUser[0].email, + social_id: foundUser[0].social_id, + image: foundUser[0].image, + image_thumbnail: foundUser[0].image_thumbnail, + verification_status: foundUser[0].verification_status, + social_login: foundUser[0].social_login, + social_platform: foundUser[0].social_platform, + csrf_k: csrfKey, + logged_in_status: true, + date: Date.now(), + }; + + if (additionalFields && Object.keys(additionalFields).length > 0) { + Object.keys(additionalFields).forEach((key) => { + // @ts-ignore + userPayload[key] = foundUser[0][key]; + }); + } + + let encryptedPayload = encrypt({ + data: JSON.stringify(userPayload), + encryptionKey, + encryptionSalt, + }); + + if (res?.setHeader) { + res.setHeader("Set-Cookie", [`datasquirelAuthKey=${encryptedPayload};samesite=strict;path=/;HttpOnly=true;Secure=true`, `csrf=${csrfKey};samesite=strict;path=/;HttpOnly=true`]); + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + return { + success: true, + user: userPayload, + }; +} + +module.exports = handleSocialDb; diff --git a/engine/user/social/utils/httpsRequest.js b/engine/user/social/utils/httpsRequest.js index c050aac..106be4c 100644 --- a/engine/user/social/utils/httpsRequest.js +++ b/engine/user/social/utils/httpsRequest.js @@ -1,105 +1,105 @@ -/** - * Imports - * ============================================================================== - */ -const https = require("https"); - -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// - -/** - * Main Function - * ============================================================================== - * @param {{ - * url?: string, - * method: string, - * hostname: string, - * path?: string, - * href?: string, - * headers?: object, - * body?: object, - * }} params - params - */ -function httpsRequest({ url, method, hostname, path, href, headers, body }) { - const reqPayloadString = body ? JSON.stringify(body) : null; - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - let requestOptions = { - method: method, - hostname: hostname, - port: 443, - headers: {}, - }; - - if (path) requestOptions.path = path; - if (href) requestOptions.href = href; - - if (headers) requestOptions.headers = headers; - if (body) { - requestOptions.headers["Content-Type"] = "application/json"; - requestOptions.headers["Content-Length"] = Buffer.from(reqPayloadString || "").length; - } - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - return new Promise((res, rej) => { - const httpsRequest = https.request( - /* ====== Request Options object ====== */ - // @ts-ignore - url ? url : requestOptions, - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - - /* ====== Callback function ====== */ - (response) => { - var str = ""; - - // ## another chunk of data has been received, so append it to `str` - response.on("data", function (chunk) { - str += chunk; - }); - - // ## the whole response has been received, so we just print it out here - response.on("end", function () { - res(str); - }); - - response.on("error", (error) => { - console.log("HTTP response error =>", error.message); - }); - } - ); - - if (body) httpsRequest.write(reqPayloadString); - - httpsRequest.on("error", (error) => { - console.log("HTTPS request ERROR =>", error); - }); - - httpsRequest.end(); - - //////////////////////////////////////////////// - //////////////////////////////////////////////// - //////////////////////////////////////////////// - }); -} - -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////// - -module.exports = httpsRequest; +/** + * Imports + * ============================================================================== + */ +const https = require("https"); + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +/** + * Main Function + * ============================================================================== + * @param {{ + * url?: string, + * method: string, + * hostname: string, + * path?: string, + * href?: string, + * headers?: object, + * body?: object, + * }} params - params + */ +function httpsRequest({ url, method, hostname, path, href, headers, body }) { + const reqPayloadString = body ? JSON.stringify(body) : null; + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + let requestOptions = { + method: method, + hostname: hostname, + port: 443, + headers: {}, + }; + + if (path) requestOptions.path = path; + if (href) requestOptions.href = href; + + if (headers) requestOptions.headers = headers; + if (body) { + requestOptions.headers["Content-Type"] = "application/json"; + requestOptions.headers["Content-Length"] = Buffer.from(reqPayloadString || "").length; + } + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + return new Promise((res, rej) => { + const httpsRequest = https.request( + /* ====== Request Options object ====== */ + // @ts-ignore + url ? url : requestOptions, + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + + /* ====== Callback function ====== */ + (response) => { + var str = ""; + + // ## another chunk of data has been received, so append it to `str` + response.on("data", function (chunk) { + str += chunk; + }); + + // ## the whole response has been received, so we just print it out here + response.on("end", function () { + res(str); + }); + + response.on("error", (error) => { + console.log("HTTP response error =>", error.message); + }); + } + ); + + if (body) httpsRequest.write(reqPayloadString); + + httpsRequest.on("error", (error) => { + console.log("HTTPS request ERROR =>", error); + }); + + httpsRequest.end(); + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + //////////////////////////////////////////////// + }); +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +module.exports = httpsRequest; diff --git a/engine/user/update-user.js b/engine/user/update-user.js index de02440..487d71b 100644 --- a/engine/user/update-user.js +++ b/engine/user/update-user.js @@ -1,85 +1,85 @@ -// @ts-check - -const updateDbEntry = require("../query/utils/updateDbEntry"); - -/** - * @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 {*} 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 localUpdateUser({ payload, dbSchema }) { - try { - /** - * User auth - * - * @description Authenticate user - */ - /** - * Initialize Variables - */ - const dbFullName = process.env.DSQL_DB_NAME || ""; - - const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; - const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; - - const data = (() => { - const reqBodyKeys = Object.keys(payload); - const finalData = {}; - - reqBodyKeys.forEach((key) => { - if (key?.match(/^date_|^id$/)) return; - // @ts-ignore - finalData[key] = payload[key]; - }); - - return finalData; - })(); - - const tableSchema = dbSchema.tables.find((tb) => tb?.tableName === "users"); - - const updateUser = await updateDbEntry({ - dbContext: "Dsql User", - paradigm: "Full Access", - dbFullName: dbFullName, - tableName: "users", - identifierColumnName: "id", - identifierValue: payload.id, - data: data, - encryptionKey, - encryptionSalt, - tableSchema, - }); - - return { - success: true, - payload: updateUser, - }; - } catch (/** @type {*} */ error) { - //////////////////////////////////////// - console.log("Error in local add-user Request =>", error.message); - - return { - success: false, - payload: null, - msg: "Something went wrong!", - }; - - //////////////////////////////////////// - } -} - -module.exports = localUpdateUser; +// @ts-check + +const updateDbEntry = require("../query/utils/updateDbEntry"); + +/** + * @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 {*} 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 localUpdateUser({ payload, dbSchema }) { + try { + /** + * User auth + * + * @description Authenticate user + */ + /** + * Initialize Variables + */ + const dbFullName = process.env.DSQL_DB_NAME || ""; + + const encryptionKey = process.env.DSQL_ENCRYPTION_KEY || ""; + const encryptionSalt = process.env.DSQL_ENCRYPTION_SALT || ""; + + const data = (() => { + const reqBodyKeys = Object.keys(payload); + const finalData = {}; + + reqBodyKeys.forEach((key) => { + if (key?.match(/^date_|^id$/)) return; + // @ts-ignore + finalData[key] = payload[key]; + }); + + return finalData; + })(); + + const tableSchema = dbSchema.tables.find((tb) => tb?.tableName === "users"); + + const updateUser = await updateDbEntry({ + dbContext: "Dsql User", + paradigm: "Full Access", + dbFullName: dbFullName, + tableName: "users", + identifierColumnName: "id", + identifierValue: payload.id, + data: data, + encryptionKey, + encryptionSalt, + tableSchema, + }); + + return { + success: true, + payload: updateUser, + }; + } catch (/** @type {*} */ error) { + //////////////////////////////////////// + console.log("Error in local add-user Request =>", error.message); + + return { + success: false, + payload: null, + msg: "Something went wrong!", + }; + + //////////////////////////////////////// + } +} + +module.exports = localUpdateUser; diff --git a/functions/decrypt.js b/functions/decrypt.js index 294452d..f4d194c 100644 --- a/functions/decrypt.js +++ b/functions/decrypt.js @@ -1,46 +1,46 @@ -// @ts-check - -const { scryptSync, createDecipheriv } = require("crypto"); -const { Buffer } = require("buffer"); - -/** - * - * @param {object} param0 - * @param {string} param0.encryptedString - * @param {string} param0.encryptionKey - * @param {string} param0.encryptionSalt - * @returns - */ -const decrypt = ({ encryptedString, encryptionKey, encryptionSalt }) => { - if (!encryptedString?.match(/./)) { - console.log("Encrypted string is invalid"); - return encryptedString; - } - - if (!encryptionKey?.match(/.{8,}/)) { - console.log("Decrption key is invalid"); - return encryptedString; - } - - if (!encryptionSalt?.match(/.{8,}/)) { - console.log("Decrption salt is invalid"); - return encryptedString; - } - - const algorithm = "aes-192-cbc"; - - let key = scryptSync(encryptionKey, encryptionSalt, 24); - let iv = Buffer.alloc(16, 0); - const decipher = createDecipheriv(algorithm, key, iv); - - try { - let decrypted = decipher.update(encryptedString, "hex", "utf8"); - decrypted += decipher.final("utf8"); - return decrypted; - } catch (/** @type {*} */ error) { - console.log("Error in decrypting =>", error.message); - return encryptedString; - } -}; - -module.exports = decrypt; +// @ts-check + +const { scryptSync, createDecipheriv } = require("crypto"); +const { Buffer } = require("buffer"); + +/** + * + * @param {object} param0 + * @param {string} param0.encryptedString + * @param {string} param0.encryptionKey + * @param {string} param0.encryptionSalt + * @returns + */ +const decrypt = ({ encryptedString, encryptionKey, encryptionSalt }) => { + if (!encryptedString?.match(/./)) { + console.log("Encrypted string is invalid"); + return encryptedString; + } + + if (!encryptionKey?.match(/.{8,}/)) { + console.log("Decrption key is invalid"); + return encryptedString; + } + + if (!encryptionSalt?.match(/.{8,}/)) { + console.log("Decrption salt is invalid"); + return encryptedString; + } + + const algorithm = "aes-192-cbc"; + + let key = scryptSync(encryptionKey, encryptionSalt, 24); + let iv = Buffer.alloc(16, 0); + const decipher = createDecipheriv(algorithm, key, iv); + + try { + let decrypted = decipher.update(encryptedString, "hex", "utf8"); + decrypted += decipher.final("utf8"); + return decrypted; + } catch (/** @type {*} */ error) { + console.log("Error in decrypting =>", error.message); + return encryptedString; + } +}; + +module.exports = decrypt; diff --git a/functions/encrypt.js b/functions/encrypt.js index 5c3fc6e..dab1953 100644 --- a/functions/encrypt.js +++ b/functions/encrypt.js @@ -1,45 +1,45 @@ -// @ts-check - -const { scryptSync, createCipheriv } = require("crypto"); -const { Buffer } = require("buffer"); - -/** - * - * @param {object} param0 - * @param {string} param0.data - * @param {string} param0.encryptionKey - * @param {string} param0.encryptionSalt - * @returns {string | null} - */ -const encrypt = ({ data, encryptionKey, encryptionSalt }) => { - if (!data?.match(/./)) { - console.log("Encryption string is invalid"); - return data; - } - if (!encryptionKey?.match(/.{8,}/)) { - console.log("Encryption key is invalid"); - return data; - } - if (!encryptionSalt?.match(/.{8,}/)) { - console.log("Encryption salt is invalid"); - return data; - } - - const algorithm = "aes-192-cbc"; - const password = encryptionKey; - - let key = scryptSync(password, encryptionSalt, 24); - let iv = Buffer.alloc(16, 0); - const cipher = createCipheriv(algorithm, key, iv); - - try { - let encrypted = cipher.update(data, "utf8", "hex"); - encrypted += cipher.final("hex"); - return encrypted; - } catch (/** @type {*} */ error) { - console.log("Error in encrypting =>", error.message); - return data; - } -}; - -module.exports = encrypt; +// @ts-check + +const { scryptSync, createCipheriv } = require("crypto"); +const { Buffer } = require("buffer"); + +/** + * + * @param {object} param0 + * @param {string} param0.data + * @param {string} param0.encryptionKey + * @param {string} param0.encryptionSalt + * @returns {string | null} + */ +const encrypt = ({ data, encryptionKey, encryptionSalt }) => { + if (!data?.match(/./)) { + console.log("Encryption string is invalid"); + return data; + } + if (!encryptionKey?.match(/.{8,}/)) { + console.log("Encryption key is invalid"); + return data; + } + if (!encryptionSalt?.match(/.{8,}/)) { + console.log("Encryption salt is invalid"); + return data; + } + + const algorithm = "aes-192-cbc"; + const password = encryptionKey; + + let key = scryptSync(password, encryptionSalt, 24); + let iv = Buffer.alloc(16, 0); + const cipher = createCipheriv(algorithm, key, iv); + + try { + let encrypted = cipher.update(data, "utf8", "hex"); + encrypted += cipher.final("hex"); + return encrypted; + } catch (/** @type {*} */ error) { + console.log("Error in encrypting =>", error.message); + return data; + } +}; + +module.exports = encrypt; diff --git a/functions/hashPassword.js b/functions/hashPassword.js index d082d4f..f511ea4 100644 --- a/functions/hashPassword.js +++ b/functions/hashPassword.js @@ -1,27 +1,27 @@ -/** # MODULE TRACE -====================================================================== - * Detected 4 files that call this module. The files are listed below: -====================================================================== - * `require` Statement Found in [add-user.js] => file:///d:\GitHub\dsql\engine\user\add-user.js - * `require` Statement Found in [login-user.js] => file:///d:\GitHub\dsql\engine\user\login-user.js - * `require` Statement Found in [googleLogin.js] => file:///d:\GitHub\dsql\engine\user\social\utils\googleLogin.js - * `require` Statement Found in [update-user.js] => file:///d:\GitHub\dsql\engine\user\update-user.js -==== MODULE TRACE END ==== */ - -// @ts-check - -const { createHmac } = require("crypto"); - -/** - * # Hash password Function - * @param {object} param0 - * @param {string} param0.password - Password to hash - * @param {string} param0.encryptionKey - Encryption key - * @returns {string} - */ -module.exports = function hashPassword({ password, encryptionKey }) { - const hmac = createHmac("sha512", encryptionKey); - hmac.update(password); - let hashed = hmac.digest("base64"); - return hashed; -}; +/** # MODULE TRACE +====================================================================== + * Detected 4 files that call this module. The files are listed below: +====================================================================== + * `require` Statement Found in [add-user.js] => file:///d:\GitHub\dsql\engine\user\add-user.js + * `require` Statement Found in [login-user.js] => file:///d:\GitHub\dsql\engine\user\login-user.js + * `require` Statement Found in [googleLogin.js] => file:///d:\GitHub\dsql\engine\user\social\utils\googleLogin.js + * `require` Statement Found in [update-user.js] => file:///d:\GitHub\dsql\engine\user\update-user.js +==== MODULE TRACE END ==== */ + +// @ts-check + +const { createHmac } = require("crypto"); + +/** + * # Hash password Function + * @param {object} param0 + * @param {string} param0.password - Password to hash + * @param {string} param0.encryptionKey - Encryption key + * @returns {string} + */ +module.exports = function hashPassword({ password, encryptionKey }) { + const hmac = createHmac("sha512", encryptionKey); + hmac.update(password); + let hashed = hmac.digest("base64"); + return hashed; +}; diff --git a/package.json b/package.json index 6a301f4..e75ff68 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "datasquirel", - "version": "1.9.0", + "version": "1.9.2", "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 bf4a285..ec4fff9 100644 --- a/types/database-schema.td.js +++ b/types/database-schema.td.js @@ -1,95 +1,95 @@ -/** - * @typedef {string} DSQL_DatabaseFullName - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" - */ - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -/** - * @typedef {object} DSQL_DatabaseSchemaType - * @property {string} dbName - Database Full name with spaces => "New Database" - * @property {string} dbSlug - Database Slug => "new_database" - * @property {string} dbFullName - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" - * @property {string} [dbDescription] - Database brief description - * @property {string} [dbImage] - Database image - Defaults to "/images/default.png" - * @property {DSQL_TableSchemaType[]} tables - List of database tables - * @property {{ dbFullName: string }[]} [childrenDatabases] - List of children databases for current database which is parent - * @property {boolean} [childDatabase] - If current database is a child of a different parent database - * @property {string} [childDatabaseDbFullName] - Parent database full name => "datasquirel_user_7_new_database" - */ - -//////////////////////////////////////// - -/** - * @typedef {object} DSQL_TableSchemaType - * @property {string} tableName - Table slug (blog_posts) - * @property {string} tableFullName - Table full name with spaces => "Blog Posts" - * @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 {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" - * @property {string} [tableNameOld] - Old table name, incase of renaming table - */ - -/** - * @typedef {object} DSQL_ChildrenTablesType - * @property {string} dbNameFull - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" - * @property {string} tableName - Table slug => "blog_posts" - */ - -//////////////////////////////////////// - -/** - * @typedef {object} DSQL_FieldSchemaType - * @property {string} fieldName - Field Name(slug) => "long_description" - * @property {string} [originName] - Field origin name(optional) - * @property {boolean} [updatedField] - Has this field been renamed? - * @property {string} dataType - Field Data type => "BIGIN" | "LONGTEXT" | "VARCHAR(***)" | ... - * @property {boolean} [nullValue] - Is this a null value or not? - * @property {boolean} [notNullValue] - Is this NOT a null value? - * @property {boolean} [primaryKey] - Is this the primary key for table? - * @property {boolean} [encrypted] - Is this field value encrypted? - * @property {boolean} [autoIncrement] - Does this table primary key increment automatically? - * @property {string|number} [defaultValue] - Value of field by default - * @property {string} [defaultValueLiteral] - SQL key word which generates value automatically => "CURRENT_TIMESTAMP" - * @property {DSQL_ForeignKeyType} [foreignKey] - Field foreign key reference object - * @property {boolean} [richText] - Rich text field - * @property {string | RegExp} [pattern] - Field pattern for validation. Can be a string or a regular expression. Example: "^[a-zA-Z0-9_]*$" - * @property {string} [patternFlags] - Field pattern flags for validation. Example: "i" - */ - -/** - * @typedef {object} DSQL_ForeignKeyType - * @property {string} foreignKeyName - Unique Name of foreign key - * @property {string} destinationTableName - Reference table name(slug) => "blog_posts" - * @property {string} destinationTableColumnName - Reference column name(slug) => "id" - * @property {string} destinationTableColumnType - Reference table field type => "BIGINT" | "VARCHAR(***)" | ... - * @property {boolean} [cascadeDelete] - Does the reference table entry delete when this key is deleted? - * @property {boolean} [cascadeUpdate] - Does the reference table entry update when this key is updated? - */ - -//////////////////////////////////////// - -/** - * @typedef {object} DSQL_IndexSchemaType - * @property {string} indexName - Unique Name of index => "blog_text_index" - * @property {string} indexType - "regular" or "fullText" - * @property {DSQL_IndexTableFieldType[]} indexTableFields - List of Index table fields - * @property {string} [alias] - List of Index table fields - */ - -/** - * @typedef {object} DSQL_IndexTableFieldType - * @property {string} value - Table Field Name - * @property {string} dataType - Table Field data type "VARCHAR(***)" | "BIGINT" | ... - */ - -//////////////////////////////////////// - -exports.DSQL_TableSchemaType = DSQL_TableSchemaType; +/** + * @typedef {string} DSQL_DatabaseFullName - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" + */ + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +/** + * @typedef {object} DSQL_DatabaseSchemaType + * @property {string} dbName - Database Full name with spaces => "New Database" + * @property {string} dbSlug - Database Slug => "new_database" + * @property {string} dbFullName - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" + * @property {string} [dbDescription] - Database brief description + * @property {string} [dbImage] - Database image - Defaults to "/images/default.png" + * @property {DSQL_TableSchemaType[]} tables - List of database tables + * @property {{ dbFullName: string }[]} [childrenDatabases] - List of children databases for current database which is parent + * @property {boolean} [childDatabase] - If current database is a child of a different parent database + * @property {string} [childDatabaseDbFullName] - Parent database full name => "datasquirel_user_7_new_database" + */ + +//////////////////////////////////////// + +/** + * @typedef {object} DSQL_TableSchemaType + * @property {string} tableName - Table slug (blog_posts) + * @property {string} tableFullName - Table full name with spaces => "Blog Posts" + * @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 {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" + * @property {string} [tableNameOld] - Old table name, incase of renaming table + */ + +/** + * @typedef {object} DSQL_ChildrenTablesType + * @property {string} dbNameFull - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" + * @property {string} tableName - Table slug => "blog_posts" + */ + +//////////////////////////////////////// + +/** + * @typedef {object} DSQL_FieldSchemaType + * @property {string} fieldName - Field Name(slug) => "long_description" + * @property {string} [originName] - Field origin name(optional) + * @property {boolean} [updatedField] - Has this field been renamed? + * @property {string} dataType - Field Data type => "BIGIN" | "LONGTEXT" | "VARCHAR(***)" | ... + * @property {boolean} [nullValue] - Is this a null value or not? + * @property {boolean} [notNullValue] - Is this NOT a null value? + * @property {boolean} [primaryKey] - Is this the primary key for table? + * @property {boolean} [encrypted] - Is this field value encrypted? + * @property {boolean} [autoIncrement] - Does this table primary key increment automatically? + * @property {string|number} [defaultValue] - Value of field by default + * @property {string} [defaultValueLiteral] - SQL key word which generates value automatically => "CURRENT_TIMESTAMP" + * @property {DSQL_ForeignKeyType} [foreignKey] - Field foreign key reference object + * @property {boolean} [richText] - Rich text field + * @property {string | RegExp} [pattern] - Field pattern for validation. Can be a string or a regular expression. Example: "^[a-zA-Z0-9_]*$" + * @property {string} [patternFlags] - Field pattern flags for validation. Example: "i" + */ + +/** + * @typedef {object} DSQL_ForeignKeyType + * @property {string} foreignKeyName - Unique Name of foreign key + * @property {string} destinationTableName - Reference table name(slug) => "blog_posts" + * @property {string} destinationTableColumnName - Reference column name(slug) => "id" + * @property {string} destinationTableColumnType - Reference table field type => "BIGINT" | "VARCHAR(***)" | ... + * @property {boolean} [cascadeDelete] - Does the reference table entry delete when this key is deleted? + * @property {boolean} [cascadeUpdate] - Does the reference table entry update when this key is updated? + */ + +//////////////////////////////////////// + +/** + * @typedef {object} DSQL_IndexSchemaType + * @property {string} indexName - Unique Name of index => "blog_text_index" + * @property {string} indexType - "regular" or "fullText" + * @property {DSQL_IndexTableFieldType[]} indexTableFields - List of Index table fields + * @property {string} [alias] - List of Index table fields + */ + +/** + * @typedef {object} DSQL_IndexTableFieldType + * @property {string} value - Table Field Name + * @property {string} dataType - Table Field data type "VARCHAR(***)" | "BIGINT" | ... + */ + +//////////////////////////////////////// + +exports.DSQL_TableSchemaType = DSQL_TableSchemaType; diff --git a/types/engine.td.js b/types/engine.td.js index d064dec..ad842a2 100644 --- a/types/engine.td.js +++ b/types/engine.td.js @@ -1,89 +1,89 @@ -/** - * @typedef {string} DSQL_DatabaseFullName - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" - */ - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -/** - * @typedef {object} DSQL_DatabaseSchemaType - * @property {string} dbName - Database Full name with spaces => "New Database" - * @property {string} dbSlug - Database Slug => "new_database" - * @property {string} dbFullName - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" - * @property {string} [dbDescription] - Database brief description - * @property {string} [dbImage] - Database image - Defaults to "/images/default.png" - * @property {DSQL_TableSchemaType[]} tables - List of database tables - * @property {{ dbFullName: string }[]} [childrenDatabases] - List of children databases for current database which is parent - * @property {boolean} [childDatabase] - If current database is a child of a different parent database - * @property {string} [childDatabaseDbFullName] - Parent database full name => "datasquirel_user_7_new_database" - */ - -//////////////////////////////////////// - -/** - * @typedef {object} DSQL_TableSchemaType - * @property {string} tableName - Table slug (blog_posts) - * @property {string} tableFullName - Table full name with spaces => "Blog Posts" - * @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 {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" - * @property {string} [tableNameOld] - Old table name, incase of renaming table - */ - -/** - * @typedef {object} DSQL_ChildrenTablesType - * @property {string} dbNameFull - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" - * @property {string} tableName - Table slug => "blog_posts" - */ - -//////////////////////////////////////// - -/** - * @typedef {object} DSQL_FieldSchemaType - * @property {string} fieldName - Field Name(slug) => "long_description" - * @property {string} [originName] - Field origin name(optional) - * @property {boolean} [updatedField] - Has this field been renamed? - * @property {string} dataType - Field Data type => "BIGIN" | "LONGTEXT" | "VARCHAR(***)" | ... - * @property {boolean} [nullValue] - Is this a null value or not? - * @property {boolean} [notNullValue] - Is this NOT a null value? - * @property {boolean} [primaryKey] - Is this the primary key for table? - * @property {boolean} [encrypted] - Is this field value encrypted? - * @property {boolean} [autoIncrement] - Does this table primary key increment automatically? - * @property {string|number} [defaultValue] - Value of field by default - * @property {string} [defaultValueLiteral] - SQL key word which generates value automatically => "CURRENT_TIMESTAMP" - * @property {DSQL_ForeignKeyType} [foreignKey] - Field foreign key reference object - */ - -/** - * @typedef {object} DSQL_ForeignKeyType - * @property {string} foreignKeyName - Unique Name of foreign key - * @property {string} destinationTableName - Reference table name(slug) => "blog_posts" - * @property {string} destinationTableColumnName - Reference column name(slug) => "id" - * @property {string} destinationTableColumnType - Reference table field type => "BIGINT" | "VARCHAR(***)" | ... - * @property {boolean} [cascadeDelete] - Does the reference table entry delete when this key is deleted? - * @property {boolean} [cascadeUpdate] - Does the reference table entry update when this key is updated? - */ - -//////////////////////////////////////// - -/** - * @typedef {object} DSQL_IndexSchemaType - * @property {string} indexName - Unique Name of index => "blog_text_index" - * @property {string} indexType - "regular" or "fullText" - * @property {DSQL_IndexTableFieldType[]} indexTableFields - List of Index table fields - */ - -/** - * @typedef {object} DSQL_IndexTableFieldType - * @property {string} value - Table Field Name - * @property {string} dataType - Table Field data type "VARCHAR(***)" | "BIGINT" | ... - */ - -//////////////////////////////////////// +/** + * @typedef {string} DSQL_DatabaseFullName - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" + */ + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +/** + * @typedef {object} DSQL_DatabaseSchemaType + * @property {string} dbName - Database Full name with spaces => "New Database" + * @property {string} dbSlug - Database Slug => "new_database" + * @property {string} dbFullName - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" + * @property {string} [dbDescription] - Database brief description + * @property {string} [dbImage] - Database image - Defaults to "/images/default.png" + * @property {DSQL_TableSchemaType[]} tables - List of database tables + * @property {{ dbFullName: string }[]} [childrenDatabases] - List of children databases for current database which is parent + * @property {boolean} [childDatabase] - If current database is a child of a different parent database + * @property {string} [childDatabaseDbFullName] - Parent database full name => "datasquirel_user_7_new_database" + */ + +//////////////////////////////////////// + +/** + * @typedef {object} DSQL_TableSchemaType + * @property {string} tableName - Table slug (blog_posts) + * @property {string} tableFullName - Table full name with spaces => "Blog Posts" + * @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 {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" + * @property {string} [tableNameOld] - Old table name, incase of renaming table + */ + +/** + * @typedef {object} DSQL_ChildrenTablesType + * @property {string} dbNameFull - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" + * @property {string} tableName - Table slug => "blog_posts" + */ + +//////////////////////////////////////// + +/** + * @typedef {object} DSQL_FieldSchemaType + * @property {string} fieldName - Field Name(slug) => "long_description" + * @property {string} [originName] - Field origin name(optional) + * @property {boolean} [updatedField] - Has this field been renamed? + * @property {string} dataType - Field Data type => "BIGIN" | "LONGTEXT" | "VARCHAR(***)" | ... + * @property {boolean} [nullValue] - Is this a null value or not? + * @property {boolean} [notNullValue] - Is this NOT a null value? + * @property {boolean} [primaryKey] - Is this the primary key for table? + * @property {boolean} [encrypted] - Is this field value encrypted? + * @property {boolean} [autoIncrement] - Does this table primary key increment automatically? + * @property {string|number} [defaultValue] - Value of field by default + * @property {string} [defaultValueLiteral] - SQL key word which generates value automatically => "CURRENT_TIMESTAMP" + * @property {DSQL_ForeignKeyType} [foreignKey] - Field foreign key reference object + */ + +/** + * @typedef {object} DSQL_ForeignKeyType + * @property {string} foreignKeyName - Unique Name of foreign key + * @property {string} destinationTableName - Reference table name(slug) => "blog_posts" + * @property {string} destinationTableColumnName - Reference column name(slug) => "id" + * @property {string} destinationTableColumnType - Reference table field type => "BIGINT" | "VARCHAR(***)" | ... + * @property {boolean} [cascadeDelete] - Does the reference table entry delete when this key is deleted? + * @property {boolean} [cascadeUpdate] - Does the reference table entry update when this key is updated? + */ + +//////////////////////////////////////// + +/** + * @typedef {object} DSQL_IndexSchemaType + * @property {string} indexName - Unique Name of index => "blog_text_index" + * @property {string} indexType - "regular" or "fullText" + * @property {DSQL_IndexTableFieldType[]} indexTableFields - List of Index table fields + */ + +/** + * @typedef {object} DSQL_IndexTableFieldType + * @property {string} value - Table Field Name + * @property {string} dataType - Table Field data type "VARCHAR(***)" | "BIGINT" | ... + */ + +//////////////////////////////////////// diff --git a/types/general.td.js b/types/general.td.js index 0754a63..a92814a 100644 --- a/types/general.td.js +++ b/types/general.td.js @@ -1,11 +1,11 @@ -const http = require("http"); - -/** - * @typedef {http.IncomingMessage} Request - */ - -/** - * @typedef {http.ServerResponse} Response - */ - -module.exports = { Request, Response }; +const http = require("http"); + +/** + * @typedef {http.IncomingMessage} Request + */ + +/** + * @typedef {http.ServerResponse} Response + */ + +module.exports = { Request, Response }; diff --git a/types/mysql.td.js b/types/mysql.td.js index 1ba7d5f..5d0b3f6 100644 --- a/types/mysql.td.js +++ b/types/mysql.td.js @@ -1,48 +1,48 @@ -/** - * @typedef {object} DSQL_MYSQL_SHOW_INDEXES_Type - * @property {string} Key_name - MYSQL Index Name - * @property {string} Table - Table Name(slug) - * @property {string} Column_name - * @property {string} Collation - * @property {string} Index_type - "FULL_TEXT" | ... - * @property {string} Cardinality - * @property {string} Index_comment - * @property {string} Comment - */ - -//////////////////////////////////////// - -/** - * @typedef {object} DSQL_MYSQL_SHOW_COLUMNS_Type - * @property {string} Field - Field Name as represented in MSQL database - * @property {string} Type - varchar(***) | tinyint | bigint | ... - * @property {string} Null - * @property {string} Key - * @property {string} Default - * @property {string} Extra - */ - -//////////////////////////////////////// - -/** - * @typedef {object} DSQL_MYSQL_FOREIGN_KEYS_Type - * @property {string} CONSTRAINT_NAME - Constraint Name => "PRIMARY" | "MUL" | null | ... - * @property {string} CONSTRAINT_SCHEMA - Database name - * @property {string} TABLE_NAME - Table name - */ - -//////////////////////////////////////// - -/** - * @typedef {object} DSQL_MYSQL_user_databases_Type - * @property {number} user_id - User Id - * @property {string} db_full_name - Database full name => eg. (dataasquirel_user_2_new_database) - * @property {string} db_name - Database name with spaces => eg. (New Database) - * @property {string} db_slug - Database slug => eg. (new_database) - * @property {string} db_image - Database image path - * @property {string} db_description - Database description - * @property {number} active_clone - is Database active clone => 0 or 1 - * @property {string} active_clone_parent_db - Database parent db full name => eg. "datasquirel_user_7_wexculture" - */ - -//////////////////////////////////////// +/** + * @typedef {object} DSQL_MYSQL_SHOW_INDEXES_Type + * @property {string} Key_name - MYSQL Index Name + * @property {string} Table - Table Name(slug) + * @property {string} Column_name + * @property {string} Collation + * @property {string} Index_type - "FULL_TEXT" | ... + * @property {string} Cardinality + * @property {string} Index_comment + * @property {string} Comment + */ + +//////////////////////////////////////// + +/** + * @typedef {object} DSQL_MYSQL_SHOW_COLUMNS_Type + * @property {string} Field - Field Name as represented in MSQL database + * @property {string} Type - varchar(***) | tinyint | bigint | ... + * @property {string} Null + * @property {string} Key + * @property {string} Default + * @property {string} Extra + */ + +//////////////////////////////////////// + +/** + * @typedef {object} DSQL_MYSQL_FOREIGN_KEYS_Type + * @property {string} CONSTRAINT_NAME - Constraint Name => "PRIMARY" | "MUL" | null | ... + * @property {string} CONSTRAINT_SCHEMA - Database name + * @property {string} TABLE_NAME - Table name + */ + +//////////////////////////////////////// + +/** + * @typedef {object} DSQL_MYSQL_user_databases_Type + * @property {number} user_id - User Id + * @property {string} db_full_name - Database full name => eg. (dataasquirel_user_2_new_database) + * @property {string} db_name - Database name with spaces => eg. (New Database) + * @property {string} db_slug - Database slug => eg. (new_database) + * @property {string} db_image - Database image path + * @property {string} db_description - Database description + * @property {number} active_clone - is Database active clone => 0 or 1 + * @property {string} active_clone_parent_db - Database parent db full name => eg. "datasquirel_user_7_wexculture" + */ + +//////////////////////////////////////// diff --git a/types/user.td.js b/types/user.td.js index 96e865b..5b5e93a 100644 --- a/types/user.td.js +++ b/types/user.td.js @@ -1,15 +1,15 @@ -/** - * @typedef {object} DATASQUIREL_LoggedInUser - * @property {number} id - user id (number) - * @property {string} first_name - User First Name - * @property {string} last_name - User Last Name - * @property {string} image - User Full Image - * @property {string} image_thumbnail - User Image Thumbnail - * @property {string} [social_id] - User Social id if available - * @property {number} social_login - 0 or 1 => is this user a social user(1) or not(0) - * @property {string} csrf_k - CSRF key - * @property {boolean} logged_in_status - Is user logged in or not - * @property {boolean} [date] - Time of session creation - */ - -module.exports = { DATASQUIREL_LoggedInUser }; +/** + * @typedef {object} DATASQUIREL_LoggedInUser + * @property {number} id - user id (number) + * @property {string} first_name - User First Name + * @property {string} last_name - User Last Name + * @property {string} image - User Full Image + * @property {string} image_thumbnail - User Image Thumbnail + * @property {string} [social_id] - User Social id if available + * @property {number} social_login - 0 or 1 => is this user a social user(1) or not(0) + * @property {string} csrf_k - CSRF key + * @property {boolean} logged_in_status - Is user logged in or not + * @property {boolean} [date] - Time of session creation + */ + +module.exports = { DATASQUIREL_LoggedInUser }; diff --git a/users/add-user.js b/users/add-user.js index 984cf75..3955396 100644 --- a/users/add-user.js +++ b/users/add-user.js @@ -1,134 +1,134 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const https = require("https"); -const path = require("path"); -const fs = require("fs"); -const localAddUser = require("../engine/user/add-user"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {object} FunctionReturn - * @property {boolean} success - Did the function run successfully? - * @property {(Object[]|string)} [payload=[]] - Payload - */ - -/** - * @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?} username - Username (Optional) - */ - -/** - * Add User to Database - * ============================================================================== - * @async - * - * @param {object} props - Single object passed - * @param {string} props.key - FULL ACCESS API Key - * @param {string} props.database - Database Name - * @param {UserDataPayload} props.payload - User Data Payload - * - * @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 - * - * @description make a request to datasquirel.com - */ - const httpResponse = await new Promise((resolve, reject) => { - const reqPayload = JSON.stringify({ - payload, - database, - }); - - 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/user/add-user`, - }, - - /** - * 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); - }); - } - ); - httpsRequest.write(reqPayload); - httpsRequest.end(); - }); - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - return httpResponse; -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = addUser; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const https = require("https"); +const path = require("path"); +const fs = require("fs"); +const localAddUser = require("../engine/user/add-user"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {object} FunctionReturn + * @property {boolean} success - Did the function run successfully? + * @property {(Object[]|string)} [payload=[]] - Payload + */ + +/** + * @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?} username - Username (Optional) + */ + +/** + * Add User to Database + * ============================================================================== + * @async + * + * @param {object} props - Single object passed + * @param {string} props.key - FULL ACCESS API Key + * @param {string} props.database - Database Name + * @param {UserDataPayload} props.payload - User Data Payload + * + * @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 + * + * @description make a request to datasquirel.com + */ + const httpResponse = await new Promise((resolve, reject) => { + const reqPayload = JSON.stringify({ + payload, + database, + }); + + 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/user/add-user`, + }, + + /** + * 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); + }); + } + ); + httpsRequest.write(reqPayload); + httpsRequest.end(); + }); + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + return httpResponse; +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = addUser; diff --git a/users/get-token.js b/users/get-token.js index 360109b..00f0f62 100644 --- a/users/get-token.js +++ b/users/get-token.js @@ -1,106 +1,106 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const http = require("http"); -const decrypt = require("../functions/decrypt"); -const parseCookies = require("../utils/functions/parseCookies"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * Get just the access token for user - * ============================================================================== - * @description This Function takes in a request object and returns a user token - * string and csrf token string - * - * @param {Object} params - Arg - * @param {http.IncomingMessage} params.request - Http request object - * @param {string} params.encryptionKey - Encryption Key - * @param {string} params.encryptionSalt - Encryption Salt - * @param {string} params.database - Database Name - * - * @returns {{ key: string | undefined, csrf: string | undefined }} - */ -function getToken({ request, encryptionKey, encryptionSalt, database }) { - try { - /** - * Grab the payload - * - * @description Grab the payload - */ - const cookies = parseCookies({ request }); - const dsqluid = cookies.dsqluid; - const authKeyName = `datasquirel_${dsqluid}_${database}_auth_key`; - const csrfName = `datasquirel_${dsqluid}_${database}_csrf`; - - const key = cookies[authKeyName]; - const csrf = cookies[csrfName]; - - /** - * Grab the payload - * - * @description Grab the payload - */ - let userPayload = decrypt({ - encryptedString: key, - encryptionKey, - encryptionSalt, - }); - - /** - * Grab the payload - * - * @description Grab the payload - */ - if (!userPayload) { - return { key: undefined, csrf: undefined }; - } - - /** - * Grab the payload - * - * @description Grab the payload - */ - let userObject = JSON.parse(userPayload); - - if (!userObject.csrf_k) { - return { key: undefined, csrf: undefined }; - } - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - /** - * Return User Object - * - * @description Return User Object - */ - return { key, csrf }; - } catch (error) { - /** - * Return User Object - * - * @description Return User Object - */ - return { - key: undefined, - csrf: undefined, - }; - } -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = getToken; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const http = require("http"); +const decrypt = require("../functions/decrypt"); +const parseCookies = require("../utils/functions/parseCookies"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Get just the access token for user + * ============================================================================== + * @description This Function takes in a request object and returns a user token + * string and csrf token string + * + * @param {Object} params - Arg + * @param {http.IncomingMessage} params.request - Http request object + * @param {string} params.encryptionKey - Encryption Key + * @param {string} params.encryptionSalt - Encryption Salt + * @param {string} params.database - Database Name + * + * @returns {{ key: string | undefined, csrf: string | undefined }} + */ +function getToken({ request, encryptionKey, encryptionSalt, database }) { + try { + /** + * Grab the payload + * + * @description Grab the payload + */ + const cookies = parseCookies({ request }); + const dsqluid = cookies.dsqluid; + const authKeyName = `datasquirel_${dsqluid}_${database}_auth_key`; + const csrfName = `datasquirel_${dsqluid}_${database}_csrf`; + + const key = cookies[authKeyName]; + const csrf = cookies[csrfName]; + + /** + * Grab the payload + * + * @description Grab the payload + */ + let userPayload = decrypt({ + encryptedString: key, + encryptionKey, + encryptionSalt, + }); + + /** + * Grab the payload + * + * @description Grab the payload + */ + if (!userPayload) { + return { key: undefined, csrf: undefined }; + } + + /** + * Grab the payload + * + * @description Grab the payload + */ + let userObject = JSON.parse(userPayload); + + if (!userObject.csrf_k) { + return { key: undefined, csrf: undefined }; + } + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + /** + * Return User Object + * + * @description Return User Object + */ + return { key, csrf }; + } catch (error) { + /** + * Return User Object + * + * @description Return User Object + */ + return { + key: undefined, + csrf: undefined, + }; + } +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = getToken; diff --git a/users/get-user.js b/users/get-user.js index 90086ef..5eb6eb0 100644 --- a/users/get-user.js +++ b/users/get-user.js @@ -1,144 +1,144 @@ -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const https = require("https"); -const getLocalUser = require("../engine/user/get-user"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {object} FunctionReturn - * @property {boolean} success - Did the function run successfully? - * @property {{ - * id: number, - * first_name: string, - * last_name: string, - * username: string, - * email: string, - * phone: string, - * social_id: [string], - * image: string, - * image_thumbnail: string, - * verification_status: [number=0], - * }} payload - Payload - */ - -/** - * ============================================================================== - * Main Function - * ============================================================================== - * @async - * - * @param {object} params - Single Param object containing params - * @param {String} params.key - API Key - * @param {String} params.database - Target Database - * @param {number} params.userId - user id - * @param {string[]} [params.fields] - fields to select - * - * @returns { Promise} - */ -async function getUser({ key, userId, database, fields }) { - /** - * Initialize - */ - const defaultFields = ["id", "first_name", "last_name", "email", "username", "image", "image_thumbnail", "verification_status", "date_created", "date_created_code", "date_created_timestamp", "date_updated", "date_updated_code", "date_updated_timestamp"]; - - const updatedFields = fields && fields[0] ? [...defaultFields, ...fields] : defaultFields; - - const reqPayload = JSON.stringify({ - userId, - database, - fields: [...new Set(updatedFields)], - }); - - /** - * 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 getLocalUser({ - userId, - fields: [...new Set(updatedFields)], - dbSchema, - }); - } - } - - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - const httpResponse = await new Promise((resolve, reject) => { - 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/user/get-user`, - }, - - /** - * 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); - }); - } - ); - - httpsRequest.write(reqPayload); - httpsRequest.end(); - }); - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - return httpResponse; -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = getUser; +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const https = require("https"); +const getLocalUser = require("../engine/user/get-user"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {object} FunctionReturn + * @property {boolean} success - Did the function run successfully? + * @property {{ + * id: number, + * first_name: string, + * last_name: string, + * username: string, + * email: string, + * phone: string, + * social_id: [string], + * image: string, + * image_thumbnail: string, + * verification_status: [number=0], + * }} payload - Payload + */ + +/** + * ============================================================================== + * Main Function + * ============================================================================== + * @async + * + * @param {object} params - Single Param object containing params + * @param {String} params.key - API Key + * @param {String} params.database - Target Database + * @param {number} params.userId - user id + * @param {string[]} [params.fields] - fields to select + * + * @returns { Promise} + */ +async function getUser({ key, userId, database, fields }) { + /** + * Initialize + */ + const defaultFields = ["id", "first_name", "last_name", "email", "username", "image", "image_thumbnail", "verification_status", "date_created", "date_created_code", "date_created_timestamp", "date_updated", "date_updated_code", "date_updated_timestamp"]; + + const updatedFields = fields && fields[0] ? [...defaultFields, ...fields] : defaultFields; + + const reqPayload = JSON.stringify({ + userId, + database, + fields: [...new Set(updatedFields)], + }); + + /** + * 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 getLocalUser({ + userId, + fields: [...new Set(updatedFields)], + dbSchema, + }); + } + } + + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + const httpResponse = await new Promise((resolve, reject) => { + 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/user/get-user`, + }, + + /** + * 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); + }); + } + ); + + httpsRequest.write(reqPayload); + httpsRequest.end(); + }); + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + return httpResponse; +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = getUser; diff --git a/users/login-user.js b/users/login-user.js index a67c461..74e8afb 100644 --- a/users/login-user.js +++ b/users/login-user.js @@ -1,204 +1,204 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const http = require("http"); -const https = require("https"); -const fs = require("fs"); -const path = require("path"); -const encrypt = require("../functions/encrypt"); -const loginLocalUser = require("../engine/user/login-user"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {object} AuthenticatedUser - * @property {boolean} success - Did the function run successfully? - * @property {import("../types/user.td").DATASQUIREL_LoggedInUser | null} payload - Payload of the response - * @property {string} [msg] - An optional message - * @property {number} [userId] - An optional message - */ - -/** - * Login A user - * ============================================================================== - * @async - * - * @param {object} params - Single Param object containing params - * @param {String} params.key - FULL ACCESS API Key - * @param {String} params.database - Target Database - * @param {{ - * email?: string, - * username?: string, - * password: string, - * }} params.payload Login Email/Username and Password - * @param {string[]} [params.additionalFields] - Additional Fields to be added to the user object - * @param {http.ServerResponse} params.response - Http response object - * @param {String} params.encryptionKey - Encryption Key - * @param {String} params.encryptionSalt - Encryption Salt - * - * @returns { Promise} - */ -async function loginUser({ key, payload, database, additionalFields, response, encryptionKey, encryptionSalt }) { - /** - * Check Encryption Keys - * - * @description Check Encryption Keys - */ - if (!encryptionKey?.match(/./)) - return { - success: false, - payload: null, - msg: "Encryption Key Required", - }; - - if (!encryptionSalt?.match(/./)) - return { - success: false, - payload: null, - msg: "Encryption Salt Required", - }; - - if (encryptionKey.length < 24) - return { - success: false, - payload: null, - msg: "Encryption Key must be at least 24 characters", - }; - - if (encryptionSalt.length < 8) - return { - success: false, - payload: null, - msg: "Encryption Salt must be at least 8 characters", - }; - - /** - * Initialize HTTP response variable - */ - let httpResponse; - - /** - * 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) { - httpResponse = await loginLocalUser({ - payload, - additionalFields, - dbSchema, - }); - } - } else { - /** - * Make https request - * - * @description make a request to datasquirel.com - * - * @type {{ success: boolean, payload: import("../types/user.td").DATASQUIREL_LoggedInUser | null, userId?: number, msg?: string }} - */ - httpResponse = await new Promise((resolve, reject) => { - const reqPayload = JSON.stringify({ - payload, - database, - additionalFields, - }); - - 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/user/login-user`, - }, - - /** - * 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); - }); - } - ); - - httpsRequest.write(reqPayload); - httpsRequest.end(); - }); - } - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - if (httpResponse?.success) { - let encryptedPayload = encrypt({ - data: JSON.stringify(httpResponse.payload), - encryptionKey, - encryptionSalt, - }); - - const { userId } = httpResponse; - - const authKeyName = `datasquirel_${userId}_${database}_auth_key`; - const csrfName = `datasquirel_${userId}_${database}_csrf`; - - response.setHeader("Set-Cookie", [`${authKeyName}=${encryptedPayload};samesite=strict;path=/;HttpOnly=true;Secure=true`, `${csrfName}=${httpResponse.payload?.csrf_k};samesite=strict;path=/;HttpOnly=true`, `dsqluid=${userId};samesite=strict;path=/;HttpOnly=true`]); - } - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - return httpResponse; -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = loginUser; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const http = require("http"); +const https = require("https"); +const fs = require("fs"); +const path = require("path"); +const encrypt = require("../functions/encrypt"); +const loginLocalUser = require("../engine/user/login-user"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {object} AuthenticatedUser + * @property {boolean} success - Did the function run successfully? + * @property {import("../types/user.td").DATASQUIREL_LoggedInUser | null} payload - Payload of the response + * @property {string} [msg] - An optional message + * @property {number} [userId] - An optional message + */ + +/** + * Login A user + * ============================================================================== + * @async + * + * @param {object} params - Single Param object containing params + * @param {String} params.key - FULL ACCESS API Key + * @param {String} params.database - Target Database + * @param {{ + * email?: string, + * username?: string, + * password: string, + * }} params.payload Login Email/Username and Password + * @param {string[]} [params.additionalFields] - Additional Fields to be added to the user object + * @param {http.ServerResponse} params.response - Http response object + * @param {String} params.encryptionKey - Encryption Key + * @param {String} params.encryptionSalt - Encryption Salt + * + * @returns { Promise} + */ +async function loginUser({ key, payload, database, additionalFields, response, encryptionKey, encryptionSalt }) { + /** + * Check Encryption Keys + * + * @description Check Encryption Keys + */ + if (!encryptionKey?.match(/./)) + return { + success: false, + payload: null, + msg: "Encryption Key Required", + }; + + if (!encryptionSalt?.match(/./)) + return { + success: false, + payload: null, + msg: "Encryption Salt Required", + }; + + if (encryptionKey.length < 24) + return { + success: false, + payload: null, + msg: "Encryption Key must be at least 24 characters", + }; + + if (encryptionSalt.length < 8) + return { + success: false, + payload: null, + msg: "Encryption Salt must be at least 8 characters", + }; + + /** + * Initialize HTTP response variable + */ + let httpResponse; + + /** + * 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) { + httpResponse = await loginLocalUser({ + payload, + additionalFields, + dbSchema, + }); + } + } else { + /** + * Make https request + * + * @description make a request to datasquirel.com + * + * @type {{ success: boolean, payload: import("../types/user.td").DATASQUIREL_LoggedInUser | null, userId?: number, msg?: string }} + */ + httpResponse = await new Promise((resolve, reject) => { + const reqPayload = JSON.stringify({ + payload, + database, + additionalFields, + }); + + 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/user/login-user`, + }, + + /** + * 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); + }); + } + ); + + httpsRequest.write(reqPayload); + httpsRequest.end(); + }); + } + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + if (httpResponse?.success) { + let encryptedPayload = encrypt({ + data: JSON.stringify(httpResponse.payload), + encryptionKey, + encryptionSalt, + }); + + const { userId } = httpResponse; + + const authKeyName = `datasquirel_${userId}_${database}_auth_key`; + const csrfName = `datasquirel_${userId}_${database}_csrf`; + + response.setHeader("Set-Cookie", [`${authKeyName}=${encryptedPayload};samesite=strict;path=/;HttpOnly=true;Secure=true`, `${csrfName}=${httpResponse.payload?.csrf_k};samesite=strict;path=/;HttpOnly=true`, `dsqluid=${userId};samesite=strict;path=/;HttpOnly=true`]); + } + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + return httpResponse; +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = loginUser; diff --git a/users/logout-user.js b/users/logout-user.js index 93c96c5..5c348b5 100644 --- a/users/logout-user.js +++ b/users/logout-user.js @@ -1,74 +1,74 @@ -// @ts-check - -const http = require("http"); -const parseCookies = require("../utils/functions/parseCookies"); - -/** - * Logout user - * ============================================================================== - * @param {object} params - Single Param object containing params - * @param {http.IncomingMessage} params.request - Http request object - * @param {http.ServerResponse} params.response - Http response object - * @param {string} [params.database] - Target database name(slug): optional => If you don't - * include this you will be logged out of all datasquirel websites instead of just the target - * database - * - * @returns {{success: boolean, payload: string}} - */ -function logoutUser({ request, response, database }) { - /** - * Check Encryption Keys - * - * @description Check Encryption Keys - */ - try { - const cookies = parseCookies({ request }); - const cookiesKeys = Object.keys(cookies); - - const dbUid = cookies.dsqluid; - const keyRegexp = new RegExp(`datasquirel_${dbUid}_${database}_auth_key`); - const csrfRegexp = new RegExp(`datasquirel_${dbUid}_${database}_csrf`); - - const authKeyName = cookiesKeys.filter((cookieKey) => cookieKey.match(keyRegexp))[0]; - const csrfName = cookiesKeys.filter((cookieKey) => cookieKey.match(csrfRegexp))[0]; - - if (authKeyName && csrfName) { - response.setHeader("Set-Cookie", [`${authKeyName}=null;samesite=strict;path=/;HttpOnly=true;Secure=true`, `${csrfName}=null;samesite=strict;path=/;HttpOnly=true`, `dsqluid=null;samesite=strict;path=/;HttpOnly=true`]); - } else { - const allKeys = cookiesKeys.filter((cookieKey) => cookieKey.match(/datasquirel_.*_auth_key/)); - const allCsrfs = cookiesKeys.filter((cookieKey) => cookieKey.match(/datasquirel_.*_csrf/)); - - response.setHeader("Set-Cookie", [...allKeys.map((key) => `${key}=null;samesite=strict;path=/;HttpOnly=true;Secure=true`), ...allCsrfs.map((csrf) => `${csrf}=null;samesite=strict;path=/;HttpOnly=true`), `dsqluid=null;samesite=strict;path=/;HttpOnly=true`]); - } - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - return { - success: true, - payload: "User Logged Out", - }; - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - } catch (error) { - console.log(error); - - return { - success: false, - payload: "Logout Failed", - }; - } - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = logoutUser; +// @ts-check + +const http = require("http"); +const parseCookies = require("../utils/functions/parseCookies"); + +/** + * Logout user + * ============================================================================== + * @param {object} params - Single Param object containing params + * @param {http.IncomingMessage} params.request - Http request object + * @param {http.ServerResponse} params.response - Http response object + * @param {string} [params.database] - Target database name(slug): optional => If you don't + * include this you will be logged out of all datasquirel websites instead of just the target + * database + * + * @returns {{success: boolean, payload: string}} + */ +function logoutUser({ request, response, database }) { + /** + * Check Encryption Keys + * + * @description Check Encryption Keys + */ + try { + const cookies = parseCookies({ request }); + const cookiesKeys = Object.keys(cookies); + + const dbUid = cookies.dsqluid; + const keyRegexp = new RegExp(`datasquirel_${dbUid}_${database}_auth_key`); + const csrfRegexp = new RegExp(`datasquirel_${dbUid}_${database}_csrf`); + + const authKeyName = cookiesKeys.filter((cookieKey) => cookieKey.match(keyRegexp))[0]; + const csrfName = cookiesKeys.filter((cookieKey) => cookieKey.match(csrfRegexp))[0]; + + if (authKeyName && csrfName) { + response.setHeader("Set-Cookie", [`${authKeyName}=null;samesite=strict;path=/;HttpOnly=true;Secure=true`, `${csrfName}=null;samesite=strict;path=/;HttpOnly=true`, `dsqluid=null;samesite=strict;path=/;HttpOnly=true`]); + } else { + const allKeys = cookiesKeys.filter((cookieKey) => cookieKey.match(/datasquirel_.*_auth_key/)); + const allCsrfs = cookiesKeys.filter((cookieKey) => cookieKey.match(/datasquirel_.*_csrf/)); + + response.setHeader("Set-Cookie", [...allKeys.map((key) => `${key}=null;samesite=strict;path=/;HttpOnly=true;Secure=true`), ...allCsrfs.map((csrf) => `${csrf}=null;samesite=strict;path=/;HttpOnly=true`), `dsqluid=null;samesite=strict;path=/;HttpOnly=true`]); + } + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + return { + success: true, + payload: "User Logged Out", + }; + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + } catch (error) { + console.log(error); + + return { + success: false, + payload: "Logout Failed", + }; + } + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = logoutUser; diff --git a/users/reauth-user.js b/users/reauth-user.js index 865a549..25587a7 100644 --- a/users/reauth-user.js +++ b/users/reauth-user.js @@ -1,190 +1,190 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const http = require("http"); -const https = require("https"); -const fs = require("fs"); -const path = require("path"); -const encrypt = require("../functions/encrypt"); - -const userAuth = require("./user-auth"); -const localReauthUser = require("../engine/user/reauth-user"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {object} FunctionReturn - * @property {boolean} success - Did the function run successfully? - * @property {import("../types/user.td").DATASQUIREL_LoggedInUser | null} payload - Payload - * @property {string} [msg] - Response Message - * @property {number} [userId] - user ID - */ - -/** - * ============================================================================== - * Main Function - * ============================================================================== - * @async - * - * @param {object} params - Single Param object containing params - * @param {String} params.key - API Key - * @param {String} params.database - Target Database - * @param {http.ServerResponse} params.response - Http response object - * @param {http.IncomingMessage} params.request - Http request object - * @param {("deep" | "normal")} [params.level] - Authentication level - * @param {String} params.encryptionKey - Encryption Key - * @param {String} params.encryptionSalt - Encryption Salt - * @param {string[]} [params.additionalFields] - Additional Fields to be added to the user object - * - * @returns { Promise } - */ -async function reauthUser({ key, database, response, request, level, encryptionKey, encryptionSalt, additionalFields }) { - /** - * Check Encryption Keys - * - * @description Check Encryption Keys - */ - const existingUser = userAuth({ - database, - encryptionKey, - encryptionSalt, - level, - request, - }); - - if (!existingUser?.payload?.id) { - return { - success: false, - payload: null, - msg: "Cookie Credentials Invalid", - }; - } - - /** - * Initialize HTTP response variable - */ - let httpResponse; - - /** - * 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) { - httpResponse = await localReauthUser({ - existingUser: existingUser.payload, - additionalFields, - dbSchema, - }); - } - } else { - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - httpResponse = await new Promise((resolve, reject) => { - const reqPayload = JSON.stringify({ - existingUser: existingUser.payload, - database, - additionalFields, - }); - - 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/user/reauth-user`, - }, - - /** - * 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); - }); - } - ); - - httpsRequest.write(reqPayload); - httpsRequest.end(); - }); - } - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - if (httpResponse?.success) { - let encryptedPayload = encrypt({ - data: JSON.stringify(httpResponse.payload), - encryptionKey, - encryptionSalt, - }); - - const { userId } = httpResponse; - - const authKeyName = `datasquirel_${userId}_${database}_auth_key`; - const csrfName = `datasquirel_${userId}_${database}_csrf`; - - response.setHeader("Set-Cookie", [`${authKeyName}=${encryptedPayload};samesite=strict;path=/;HttpOnly=true;Secure=true`, `${csrfName}=${httpResponse.payload.csrf_k};samesite=strict;path=/;HttpOnly=true`, `dsqluid=${userId};samesite=strict;path=/;HttpOnly=true`]); - } - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - return httpResponse; -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = reauthUser; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const http = require("http"); +const https = require("https"); +const fs = require("fs"); +const path = require("path"); +const encrypt = require("../functions/encrypt"); + +const userAuth = require("./user-auth"); +const localReauthUser = require("../engine/user/reauth-user"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {object} FunctionReturn + * @property {boolean} success - Did the function run successfully? + * @property {import("../types/user.td").DATASQUIREL_LoggedInUser | null} payload - Payload + * @property {string} [msg] - Response Message + * @property {number} [userId] - user ID + */ + +/** + * ============================================================================== + * Main Function + * ============================================================================== + * @async + * + * @param {object} params - Single Param object containing params + * @param {String} params.key - API Key + * @param {String} params.database - Target Database + * @param {http.ServerResponse} params.response - Http response object + * @param {http.IncomingMessage} params.request - Http request object + * @param {("deep" | "normal")} [params.level] - Authentication level + * @param {String} params.encryptionKey - Encryption Key + * @param {String} params.encryptionSalt - Encryption Salt + * @param {string[]} [params.additionalFields] - Additional Fields to be added to the user object + * + * @returns { Promise } + */ +async function reauthUser({ key, database, response, request, level, encryptionKey, encryptionSalt, additionalFields }) { + /** + * Check Encryption Keys + * + * @description Check Encryption Keys + */ + const existingUser = userAuth({ + database, + encryptionKey, + encryptionSalt, + level, + request, + }); + + if (!existingUser?.payload?.id) { + return { + success: false, + payload: null, + msg: "Cookie Credentials Invalid", + }; + } + + /** + * Initialize HTTP response variable + */ + let httpResponse; + + /** + * 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) { + httpResponse = await localReauthUser({ + existingUser: existingUser.payload, + additionalFields, + dbSchema, + }); + } + } else { + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + httpResponse = await new Promise((resolve, reject) => { + const reqPayload = JSON.stringify({ + existingUser: existingUser.payload, + database, + additionalFields, + }); + + 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/user/reauth-user`, + }, + + /** + * 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); + }); + } + ); + + httpsRequest.write(reqPayload); + httpsRequest.end(); + }); + } + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + if (httpResponse?.success) { + let encryptedPayload = encrypt({ + data: JSON.stringify(httpResponse.payload), + encryptionKey, + encryptionSalt, + }); + + const { userId } = httpResponse; + + const authKeyName = `datasquirel_${userId}_${database}_auth_key`; + const csrfName = `datasquirel_${userId}_${database}_csrf`; + + response.setHeader("Set-Cookie", [`${authKeyName}=${encryptedPayload};samesite=strict;path=/;HttpOnly=true;Secure=true`, `${csrfName}=${httpResponse.payload.csrf_k};samesite=strict;path=/;HttpOnly=true`, `dsqluid=${userId};samesite=strict;path=/;HttpOnly=true`]); + } + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + return httpResponse; +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = reauthUser; diff --git a/users/social/github-auth.js b/users/social/github-auth.js index 3cd50a9..13e5239 100644 --- a/users/social/github-auth.js +++ b/users/social/github-auth.js @@ -1,251 +1,251 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const http = require("http"); -const https = require("https"); -const fs = require("fs"); -const path = require("path"); -const encrypt = require("../../functions/encrypt"); -const localGithubAuth = require("../../engine/user/social/github-auth"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {object} FunctionReturn - * @property {boolean} success - Did the function run successfully? - * @property {{id: number, first_name: string, last_name: string, csrf_k: string, social_id: string} | null} user - Returned User - * @property {number} [dsqlUserId] - Dsql User Id - * @property {string} [msg] - Response message - */ - -/** - * SERVER FUNCTION: Login with google Function - * ============================================================================== - * - * @async - * - * @param {object} params - main params object - * @param {string} params.key - API full access key - * @param {string} params.code - Github access code gotten from the client side - * @param {string?} params.email - Email gotten from the client side if available - * @param {string} params.database - Target database name(slug) - * @param {string} params.clientId - Github client id - * @param {string} params.clientSecret - Github client Secret - * @param {http.ServerResponse} params.response - HTTPS response object - * @param {string} params.encryptionKey - Encryption key - * @param {string} params.encryptionSalt - Encryption salt - * @param {object} [params.additionalFields] - Additional Fields to be added to the user object - * - * @returns { Promise } - */ -async function githubAuth({ key, code, email, database, clientId, clientSecret, response, encryptionKey, encryptionSalt, additionalFields }) { - /** - * Check inputs - * - * @description Check inputs - */ - if (!key || key?.match(/ /)) { - return { - success: false, - user: null, - msg: "Please enter API full access Key", - }; - } - - if (!code || code?.match(/ /)) { - return { - success: false, - user: null, - msg: "Please enter Github Access Token", - }; - } - - if (!database || database?.match(/ /)) { - return { - success: false, - user: null, - msg: "Please provide database slug name you want to access", - }; - } - - if (!clientId || clientId?.match(/ /)) { - return { - success: false, - user: null, - msg: "Please enter Github OAUTH client ID", - }; - } - - if (!response || !response?.setHeader) { - return { - success: false, - user: null, - msg: "Please provide a valid HTTPS response object", - }; - } - - if (!encryptionKey || encryptionKey?.match(/ /)) { - return { - success: false, - user: null, - msg: "Please provide a valid encryption key", - }; - } - - if (!encryptionSalt || encryptionSalt?.match(/ /)) { - return { - success: false, - user: null, - msg: "Please provide a valid encryption salt", - }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Initialize HTTP response variable - */ - let httpResponse; - - /** - * 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) { - httpResponse = await localGithubAuth({ - dbSchema: dbSchema, - code, - email: email || undefined, - clientId, - clientSecret, - additionalFields, - res: response, - }); - } - } else { - /** - * Make https request - * - * @description make a request to datasquirel.com - * @type {FunctionReturn} - Https response object - */ - httpResponse = await new Promise((resolve, reject) => { - const reqPayload = JSON.stringify({ - code, - email, - clientId, - clientSecret, - database, - additionalFields, - }); - - 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/user/github-login`, - }, - - /** - * 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); - - resolve({ - success: false, - user: null, - msg: "Something went wrong", - }); - } - }); - - response.on("error", (err) => { - reject(err); - }); - } - ); - httpsRequest.write(reqPayload); - httpsRequest.end(); - }); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - if (httpResponse?.success && httpResponse?.user) { - let encryptedPayload = encrypt({ - data: JSON.stringify(httpResponse.user), - encryptionKey, - encryptionSalt, - }); - - const { user, dsqlUserId } = httpResponse; - - const authKeyName = `datasquirel_${dsqlUserId}_${database}_auth_key`; - const csrfName = `datasquirel_${dsqlUserId}_${database}_csrf`; - - response.setHeader("Set-Cookie", [`${authKeyName}=${encryptedPayload};samesite=strict;path=/;HttpOnly=true;Secure=true`, `${csrfName}=${user.csrf_k};samesite=strict;path=/;HttpOnly=true`, `dsqluid=${dsqlUserId};samesite=strict;path=/;HttpOnly=true`, `datasquirel_social_id=${user.social_id};samesite=strict;path=/`]); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - return httpResponse; -} - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -module.exports = githubAuth; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const http = require("http"); +const https = require("https"); +const fs = require("fs"); +const path = require("path"); +const encrypt = require("../../functions/encrypt"); +const localGithubAuth = require("../../engine/user/social/github-auth"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {object} FunctionReturn + * @property {boolean} success - Did the function run successfully? + * @property {{id: number, first_name: string, last_name: string, csrf_k: string, social_id: string} | null} user - Returned User + * @property {number} [dsqlUserId] - Dsql User Id + * @property {string} [msg] - Response message + */ + +/** + * SERVER FUNCTION: Login with google Function + * ============================================================================== + * + * @async + * + * @param {object} params - main params object + * @param {string} params.key - API full access key + * @param {string} params.code - Github access code gotten from the client side + * @param {string?} params.email - Email gotten from the client side if available + * @param {string} params.database - Target database name(slug) + * @param {string} params.clientId - Github client id + * @param {string} params.clientSecret - Github client Secret + * @param {http.ServerResponse} params.response - HTTPS response object + * @param {string} params.encryptionKey - Encryption key + * @param {string} params.encryptionSalt - Encryption salt + * @param {object} [params.additionalFields] - Additional Fields to be added to the user object + * + * @returns { Promise } + */ +async function githubAuth({ key, code, email, database, clientId, clientSecret, response, encryptionKey, encryptionSalt, additionalFields }) { + /** + * Check inputs + * + * @description Check inputs + */ + if (!key || key?.match(/ /)) { + return { + success: false, + user: null, + msg: "Please enter API full access Key", + }; + } + + if (!code || code?.match(/ /)) { + return { + success: false, + user: null, + msg: "Please enter Github Access Token", + }; + } + + if (!database || database?.match(/ /)) { + return { + success: false, + user: null, + msg: "Please provide database slug name you want to access", + }; + } + + if (!clientId || clientId?.match(/ /)) { + return { + success: false, + user: null, + msg: "Please enter Github OAUTH client ID", + }; + } + + if (!response || !response?.setHeader) { + return { + success: false, + user: null, + msg: "Please provide a valid HTTPS response object", + }; + } + + if (!encryptionKey || encryptionKey?.match(/ /)) { + return { + success: false, + user: null, + msg: "Please provide a valid encryption key", + }; + } + + if (!encryptionSalt || encryptionSalt?.match(/ /)) { + return { + success: false, + user: null, + msg: "Please provide a valid encryption salt", + }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Initialize HTTP response variable + */ + let httpResponse; + + /** + * 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) { + httpResponse = await localGithubAuth({ + dbSchema: dbSchema, + code, + email: email || undefined, + clientId, + clientSecret, + additionalFields, + res: response, + }); + } + } else { + /** + * Make https request + * + * @description make a request to datasquirel.com + * @type {FunctionReturn} - Https response object + */ + httpResponse = await new Promise((resolve, reject) => { + const reqPayload = JSON.stringify({ + code, + email, + clientId, + clientSecret, + database, + additionalFields, + }); + + 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/user/github-login`, + }, + + /** + * 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); + + resolve({ + success: false, + user: null, + msg: "Something went wrong", + }); + } + }); + + response.on("error", (err) => { + reject(err); + }); + } + ); + httpsRequest.write(reqPayload); + httpsRequest.end(); + }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + if (httpResponse?.success && httpResponse?.user) { + let encryptedPayload = encrypt({ + data: JSON.stringify(httpResponse.user), + encryptionKey, + encryptionSalt, + }); + + const { user, dsqlUserId } = httpResponse; + + const authKeyName = `datasquirel_${dsqlUserId}_${database}_auth_key`; + const csrfName = `datasquirel_${dsqlUserId}_${database}_csrf`; + + response.setHeader("Set-Cookie", [`${authKeyName}=${encryptedPayload};samesite=strict;path=/;HttpOnly=true;Secure=true`, `${csrfName}=${user.csrf_k};samesite=strict;path=/;HttpOnly=true`, `dsqluid=${dsqlUserId};samesite=strict;path=/;HttpOnly=true`, `datasquirel_social_id=${user.social_id};samesite=strict;path=/`]); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + return httpResponse; +} + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +module.exports = githubAuth; diff --git a/users/social/google-auth.js b/users/social/google-auth.js index 4e9e7e0..23e7ac1 100644 --- a/users/social/google-auth.js +++ b/users/social/google-auth.js @@ -1,239 +1,239 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const http = require("http"); -const https = require("https"); -const fs = require("fs"); -const path = require("path"); -const encrypt = require("../../functions/encrypt"); -const localGoogleAuth = require("../../engine/user/social/google-auth"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {object | null} FunctionReturn - * @property {boolean} success - Did the function run successfully? - * @property {import("../../types/user.td").DATASQUIREL_LoggedInUser | null} user - Returned User - * @property {number} [dsqlUserId] - Dsql User Id - * @property {string} [msg] - Response message - */ - -/** - * SERVER FUNCTION: Login with google Function - * ============================================================================== - * - * @async - * - * @param {object} params - main params object - * @param {string} params.key - API full access key - * @param {string} params.token - Google access token gotten from the client side - * @param {string} params.database - Target database name(slug) - * @param {string} params.clientId - Google client id - * @param {http.ServerResponse} params.response - HTTPS response object - * @param {string} params.encryptionKey - Encryption key - * @param {string} params.encryptionSalt - Encryption salt - * @param {object} [params.additionalFields] - Additional Fields to be added to the user object - * - * @returns { Promise } - */ -async function googleAuth({ key, token, database, clientId, response, encryptionKey, encryptionSalt, additionalFields }) { - /** - * Check inputs - * - * @description Check inputs - */ - if (!key || key?.match(/ /)) { - return { - success: false, - user: null, - msg: "Please enter API full access Key", - }; - } - - if (!token || token?.match(/ /)) { - return { - success: false, - user: null, - msg: "Please enter Google Access Token", - }; - } - - if (!database || database?.match(/ /)) { - return { - success: false, - user: null, - msg: "Please provide database slug name you want to access", - }; - } - - if (!clientId || clientId?.match(/ /)) { - return { - success: false, - user: null, - msg: "Please enter Google OAUTH client ID", - }; - } - - if (!response || !response?.setHeader) { - return { - success: false, - user: null, - msg: "Please provide a valid HTTPS response object", - }; - } - - if (!encryptionKey || encryptionKey?.match(/ /)) { - return { - success: false, - user: null, - msg: "Please provide a valid encryption key", - }; - } - - if (!encryptionSalt || encryptionSalt?.match(/ /)) { - return { - success: false, - user: null, - msg: "Please provide a valid encryption salt", - }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Initialize HTTP response variable - */ - let httpResponse; - - /** - * 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) { - httpResponse = await localGoogleAuth({ - dbSchema: dbSchema, - token, - clientId, - additionalFields, - response: response, - }); - } - } else { - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Make https request - * - * @description make a request to datasquirel.com - * @type {{ success: boolean, user: import("../../types/user.td").DATASQUIREL_LoggedInUser | null, msg?: string, dsqlUserId?: number } | null } - Https response object - */ - httpResponse = await new Promise((resolve, reject) => { - const reqPayload = JSON.stringify({ - token, - clientId, - database, - additionalFields, - }); - - 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/user/google-login`, - }, - - /** - * 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); - }); - } - ); - httpsRequest.write(reqPayload); - httpsRequest.end(); - }); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - if (httpResponse?.success && httpResponse?.user) { - let encryptedPayload = encrypt({ - data: JSON.stringify(httpResponse.user), - encryptionKey, - encryptionSalt, - }); - - const { user, dsqlUserId } = httpResponse; - - const authKeyName = `datasquirel_${dsqlUserId}_${database}_auth_key`; - const csrfName = `datasquirel_${dsqlUserId}_${database}_csrf`; - - response.setHeader("Set-Cookie", [`${authKeyName}=${encryptedPayload};samesite=strict;path=/;HttpOnly=true;Secure=true`, `${csrfName}=${user.csrf_k};samesite=strict;path=/;HttpOnly=true`, `dsqluid=${dsqlUserId};samesite=strict;path=/;HttpOnly=true`, `datasquirel_social_id=${user.social_id};samesite=strict;path=/`]); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - return httpResponse; -} - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// - -module.exports = googleAuth; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const http = require("http"); +const https = require("https"); +const fs = require("fs"); +const path = require("path"); +const encrypt = require("../../functions/encrypt"); +const localGoogleAuth = require("../../engine/user/social/google-auth"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {object | null} FunctionReturn + * @property {boolean} success - Did the function run successfully? + * @property {import("../../types/user.td").DATASQUIREL_LoggedInUser | null} user - Returned User + * @property {number} [dsqlUserId] - Dsql User Id + * @property {string} [msg] - Response message + */ + +/** + * SERVER FUNCTION: Login with google Function + * ============================================================================== + * + * @async + * + * @param {object} params - main params object + * @param {string} params.key - API full access key + * @param {string} params.token - Google access token gotten from the client side + * @param {string} params.database - Target database name(slug) + * @param {string} params.clientId - Google client id + * @param {http.ServerResponse} params.response - HTTPS response object + * @param {string} params.encryptionKey - Encryption key + * @param {string} params.encryptionSalt - Encryption salt + * @param {object} [params.additionalFields] - Additional Fields to be added to the user object + * + * @returns { Promise } + */ +async function googleAuth({ key, token, database, clientId, response, encryptionKey, encryptionSalt, additionalFields }) { + /** + * Check inputs + * + * @description Check inputs + */ + if (!key || key?.match(/ /)) { + return { + success: false, + user: null, + msg: "Please enter API full access Key", + }; + } + + if (!token || token?.match(/ /)) { + return { + success: false, + user: null, + msg: "Please enter Google Access Token", + }; + } + + if (!database || database?.match(/ /)) { + return { + success: false, + user: null, + msg: "Please provide database slug name you want to access", + }; + } + + if (!clientId || clientId?.match(/ /)) { + return { + success: false, + user: null, + msg: "Please enter Google OAUTH client ID", + }; + } + + if (!response || !response?.setHeader) { + return { + success: false, + user: null, + msg: "Please provide a valid HTTPS response object", + }; + } + + if (!encryptionKey || encryptionKey?.match(/ /)) { + return { + success: false, + user: null, + msg: "Please provide a valid encryption key", + }; + } + + if (!encryptionSalt || encryptionSalt?.match(/ /)) { + return { + success: false, + user: null, + msg: "Please provide a valid encryption salt", + }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Initialize HTTP response variable + */ + let httpResponse; + + /** + * 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) { + httpResponse = await localGoogleAuth({ + dbSchema: dbSchema, + token, + clientId, + additionalFields, + response: response, + }); + } + } else { + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Make https request + * + * @description make a request to datasquirel.com + * @type {{ success: boolean, user: import("../../types/user.td").DATASQUIREL_LoggedInUser | null, msg?: string, dsqlUserId?: number } | null } - Https response object + */ + httpResponse = await new Promise((resolve, reject) => { + const reqPayload = JSON.stringify({ + token, + clientId, + database, + additionalFields, + }); + + 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/user/google-login`, + }, + + /** + * 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); + }); + } + ); + httpsRequest.write(reqPayload); + httpsRequest.end(); + }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + if (httpResponse?.success && httpResponse?.user) { + let encryptedPayload = encrypt({ + data: JSON.stringify(httpResponse.user), + encryptionKey, + encryptionSalt, + }); + + const { user, dsqlUserId } = httpResponse; + + const authKeyName = `datasquirel_${dsqlUserId}_${database}_auth_key`; + const csrfName = `datasquirel_${dsqlUserId}_${database}_csrf`; + + response.setHeader("Set-Cookie", [`${authKeyName}=${encryptedPayload};samesite=strict;path=/;HttpOnly=true;Secure=true`, `${csrfName}=${user.csrf_k};samesite=strict;path=/;HttpOnly=true`, `dsqluid=${dsqlUserId};samesite=strict;path=/;HttpOnly=true`, `datasquirel_social_id=${user.social_id};samesite=strict;path=/`]); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + return httpResponse; +} + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// + +module.exports = googleAuth; diff --git a/users/update-user.js b/users/update-user.js index 8e0d7b0..3334124 100644 --- a/users/update-user.js +++ b/users/update-user.js @@ -1,126 +1,126 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const https = require("https"); -const path = require("path"); -const fs = require("fs"); -const localUpdateUser = require("../engine/user/update-user"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {object} FunctionReturn - * @property {boolean} success - Did the function run successfully? - * @property {(Object[]|string)} [payload=[]] - Payload - */ - -/** - * ============================================================================== - * Main Function - * ============================================================================== - * @async - * - * @param {object} params - API Key - * @param {String} params.key - API Key - * @param {String} params.database - Target Database - * @param {{ id: number }} params.payload - User Object - * - * @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; - - 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 localUpdateUser({ - dbSchema: dbSchema, - payload: payload, - }); - } - } - - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - const httpResponse = await new Promise((resolve, reject) => { - const reqPayload = JSON.stringify({ - payload, - database, - }); - - 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/user/update-user`, - }, - - /** - * 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); - }); - } - ); - httpsRequest.write(reqPayload); - httpsRequest.end(); - }); - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - return httpResponse; -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = updateUser; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const https = require("https"); +const path = require("path"); +const fs = require("fs"); +const localUpdateUser = require("../engine/user/update-user"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {object} FunctionReturn + * @property {boolean} success - Did the function run successfully? + * @property {(Object[]|string)} [payload=[]] - Payload + */ + +/** + * ============================================================================== + * Main Function + * ============================================================================== + * @async + * + * @param {object} params - API Key + * @param {String} params.key - API Key + * @param {String} params.database - Target Database + * @param {{ id: number }} params.payload - User Object + * + * @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; + + 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 localUpdateUser({ + dbSchema: dbSchema, + payload: payload, + }); + } + } + + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + const httpResponse = await new Promise((resolve, reject) => { + const reqPayload = JSON.stringify({ + payload, + database, + }); + + 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/user/update-user`, + }, + + /** + * 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); + }); + } + ); + httpsRequest.write(reqPayload); + httpsRequest.end(); + }); + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + return httpResponse; +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = updateUser; diff --git a/users/user-auth.js b/users/user-auth.js index 5a1ebc9..c6d4d9f 100644 --- a/users/user-auth.js +++ b/users/user-auth.js @@ -1,143 +1,143 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const http = require("http"); -const decrypt = require("../functions/decrypt"); -const parseCookies = require("../utils/functions/parseCookies"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {object} AuthenticatedUserObject - * @property {boolean} success - Did the function run successfully? - * @property {import("../types/user.td").DATASQUIREL_LoggedInUser | null} payload - Payload - * @property {string | unknown} [msg] - Response Message - */ - -/** - * Authenticate User from request - * ============================================================================== - * @description This Function takes in a request object and returns a user object - * with the user's data - * - * @param {Object} params - Arg - * @param {http.IncomingMessage} params.request - Http request object - * @param {string} params.encryptionKey - Encryption Key - * @param {string} params.encryptionSalt - Encryption Salt - * @param {("deep" | "normal")} [params.level] - Optional. "Deep" value indicates an extra layer of security - * @param {string} params.database - Database Name - * - * @returns { AuthenticatedUserObject } - */ -function userAuth({ request, encryptionKey, encryptionSalt, level, database }) { - try { - /** - * Grab the payload - * - * @description Grab the payload - */ - const cookies = parseCookies({ request }); - const dsqluid = cookies.dsqluid; - const authKeyName = `datasquirel_${dsqluid}_${database}_auth_key`; - const csrfName = `datasquirel_${dsqluid}_${database}_csrf`; - - const key = cookies[authKeyName]; - const csrf = cookies[csrfName]; - - /** - * Grab the payload - * - * @description Grab the payload - */ - let userPayload = decrypt({ - encryptedString: key, - encryptionKey, - encryptionSalt, - }); - - /** - * Grab the payload - * - * @description Grab the payload - */ - if (!userPayload) { - return { - success: false, - payload: null, - msg: "Couldn't Decrypt cookie", - }; - } - - /** - * Grab the payload - * - * @description Grab the payload - */ - let userObject = JSON.parse(userPayload); - - if (!userObject.csrf_k) { - return { - success: false, - payload: null, - msg: "No CSRF_K in decrypted payload", - }; - } - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - /** - * Grab the payload - * - * @description Grab the payload - */ - if (level?.match(/deep/i) && !csrf?.match(new RegExp(`${userObject.csrf_k}`))) { - return { - success: false, - payload: null, - msg: "CSRF_K requested but does not match payload", - }; - } - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - /** - * Return User Object - * - * @description Return User Object - */ - return { - success: true, - payload: userObject, - }; - } catch (error) { - /** - * Return User Object - * - * @description Return User Object - */ - return { - success: false, - payload: null, - msg: error, - }; - } -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = userAuth; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const http = require("http"); +const decrypt = require("../functions/decrypt"); +const parseCookies = require("../utils/functions/parseCookies"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {object} AuthenticatedUserObject + * @property {boolean} success - Did the function run successfully? + * @property {import("../types/user.td").DATASQUIREL_LoggedInUser | null} payload - Payload + * @property {string | unknown} [msg] - Response Message + */ + +/** + * Authenticate User from request + * ============================================================================== + * @description This Function takes in a request object and returns a user object + * with the user's data + * + * @param {Object} params - Arg + * @param {http.IncomingMessage} params.request - Http request object + * @param {string} params.encryptionKey - Encryption Key + * @param {string} params.encryptionSalt - Encryption Salt + * @param {("deep" | "normal")} [params.level] - Optional. "Deep" value indicates an extra layer of security + * @param {string} params.database - Database Name + * + * @returns { AuthenticatedUserObject } + */ +function userAuth({ request, encryptionKey, encryptionSalt, level, database }) { + try { + /** + * Grab the payload + * + * @description Grab the payload + */ + const cookies = parseCookies({ request }); + const dsqluid = cookies.dsqluid; + const authKeyName = `datasquirel_${dsqluid}_${database}_auth_key`; + const csrfName = `datasquirel_${dsqluid}_${database}_csrf`; + + const key = cookies[authKeyName]; + const csrf = cookies[csrfName]; + + /** + * Grab the payload + * + * @description Grab the payload + */ + let userPayload = decrypt({ + encryptedString: key, + encryptionKey, + encryptionSalt, + }); + + /** + * Grab the payload + * + * @description Grab the payload + */ + if (!userPayload) { + return { + success: false, + payload: null, + msg: "Couldn't Decrypt cookie", + }; + } + + /** + * Grab the payload + * + * @description Grab the payload + */ + let userObject = JSON.parse(userPayload); + + if (!userObject.csrf_k) { + return { + success: false, + payload: null, + msg: "No CSRF_K in decrypted payload", + }; + } + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + /** + * Grab the payload + * + * @description Grab the payload + */ + if (level?.match(/deep/i) && !csrf?.match(new RegExp(`${userObject.csrf_k}`))) { + return { + success: false, + payload: null, + msg: "CSRF_K requested but does not match payload", + }; + } + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + /** + * Return User Object + * + * @description Return User Object + */ + return { + success: true, + payload: userObject, + }; + } catch (error) { + /** + * Return User Object + * + * @description Return User Object + */ + return { + success: false, + payload: null, + msg: error, + }; + } +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = userAuth; diff --git a/users/validate-token.js b/users/validate-token.js index e920592..8a06034 100644 --- a/users/validate-token.js +++ b/users/validate-token.js @@ -1,96 +1,96 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const http = require("http"); -const decrypt = require("../functions/decrypt"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * Validate Token - * ============================================================================== - * @description This Function takes in a encrypted token and returns a user object - * - * @param {Object} params - Arg - * @param {string} params.token - Encrypted Token - * @param {string} params.encryptionKey - Encryption Key - * @param {string} params.encryptionSalt - Encryption Salt - * @param {("deep" | "normal")?} [params.level] - Optional. "Deep" value indicates an extra layer of security - * @param {string} params.database - Database Name - * - * @returns { import("../types/user.td").DATASQUIREL_LoggedInUser | null} - */ -function validateToken({ token, encryptionKey, encryptionSalt }) { - try { - /** - * Grab the payload - * - * @description Grab the payload - */ - const key = token; - - /** - * Grab the payload - * - * @description Grab the payload - */ - let userPayload = decrypt({ - encryptedString: key, - encryptionKey, - encryptionSalt, - }); - - /** - * Grab the payload - * - * @description Grab the payload - */ - if (!userPayload) { - return null; - } - - /** - * Grab the payload - * - * @description Grab the payload - */ - let userObject = JSON.parse(userPayload); - - if (!userObject.csrf_k) { - return null; - } - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - /** - * Return User Object - * - * @description Return User Object - */ - return userObject; - } catch (error) { - /** - * Return User Object - * - * @description Return User Object - */ - return null; - } -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = validateToken; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const http = require("http"); +const decrypt = require("../functions/decrypt"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Validate Token + * ============================================================================== + * @description This Function takes in a encrypted token and returns a user object + * + * @param {Object} params - Arg + * @param {string} params.token - Encrypted Token + * @param {string} params.encryptionKey - Encryption Key + * @param {string} params.encryptionSalt - Encryption Salt + * @param {("deep" | "normal")?} [params.level] - Optional. "Deep" value indicates an extra layer of security + * @param {string} params.database - Database Name + * + * @returns { import("../types/user.td").DATASQUIREL_LoggedInUser | null} + */ +function validateToken({ token, encryptionKey, encryptionSalt }) { + try { + /** + * Grab the payload + * + * @description Grab the payload + */ + const key = token; + + /** + * Grab the payload + * + * @description Grab the payload + */ + let userPayload = decrypt({ + encryptedString: key, + encryptionKey, + encryptionSalt, + }); + + /** + * Grab the payload + * + * @description Grab the payload + */ + if (!userPayload) { + return null; + } + + /** + * Grab the payload + * + * @description Grab the payload + */ + let userObject = JSON.parse(userPayload); + + if (!userObject.csrf_k) { + return null; + } + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + /** + * Return User Object + * + * @description Return User Object + */ + return userObject; + } catch (error) { + /** + * Return User Object + * + * @description Return User Object + */ + return null; + } +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = validateToken; diff --git a/utils/delete-file.js b/utils/delete-file.js index 4f69250..3957094 100644 --- a/utils/delete-file.js +++ b/utils/delete-file.js @@ -1,110 +1,110 @@ -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const https = require("https"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {Object} FunctionReturn - * @property {boolean} success - Did the function run successfully? - * @property {{ - * urlPath: string, - * urlThumbnailPath: string - * }} payload - Payload containing the url for the image and its thumbnail - * @property {string} [msg] - An optional message - */ - -/** - * ============================================================================== - * Main Function - * ============================================================================== - * @async - * - * @param {Object} params - Single Param object containing params - * @param {String} params.key - *FULL ACCESS API Key - * @param { string } params.url - File URL - * - * @returns { Promise } - Image Url - */ -async function uploadImage({ key, url }) { - try { - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - const httpResponse = await new Promise((resolve, reject) => { - const reqPayload = JSON.stringify({ url: url }); - - 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/delete-file`, - }, - - /** - * 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); - }); - } - ); - - httpsRequest.write(reqPayload); - httpsRequest.end(); - }); - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - return httpResponse; - } catch (/** @type {*} */ error) { - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - console.log("Error deleting file: ", error.message); - - return { - success: false, - payload: null, - msg: error.message, - }; - } -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = uploadImage; +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const https = require("https"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {Object} FunctionReturn + * @property {boolean} success - Did the function run successfully? + * @property {{ + * urlPath: string, + * urlThumbnailPath: string + * }} payload - Payload containing the url for the image and its thumbnail + * @property {string} [msg] - An optional message + */ + +/** + * ============================================================================== + * Main Function + * ============================================================================== + * @async + * + * @param {Object} params - Single Param object containing params + * @param {String} params.key - *FULL ACCESS API Key + * @param { string } params.url - File URL + * + * @returns { Promise } - Image Url + */ +async function uploadImage({ key, url }) { + try { + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + const httpResponse = await new Promise((resolve, reject) => { + const reqPayload = JSON.stringify({ url: url }); + + 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/delete-file`, + }, + + /** + * 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); + }); + } + ); + + httpsRequest.write(reqPayload); + httpsRequest.end(); + }); + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + return httpResponse; + } catch (/** @type {*} */ error) { + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + console.log("Error deleting file: ", error.message); + + return { + success: false, + payload: null, + msg: error.message, + }; + } +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = uploadImage; diff --git a/utils/functions/parseCookies.js b/utils/functions/parseCookies.js index 08ccb5c..417847b 100644 --- a/utils/functions/parseCookies.js +++ b/utils/functions/parseCookies.js @@ -1,69 +1,69 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const http = require("http"); - -/** - * Parse request cookies - * ============================================================================== - * - * @description This function takes in a request object and returns the cookies as a JS object - * - * @async - * - * @param {object} params - main params object - * @param {http.IncomingMessage} params.request - HTTPS request object - * - * @returns {* | null} - */ -module.exports = function ({ request }) { - /** - * Check inputs - * - * @description Check inputs - */ - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** @type {string | undefined} */ - const cookieString = request.headers.cookie; - - if (!cookieString || typeof cookieString !== "string") { - return null; - } - - /** @type {string[]} */ - const cookieSplitArray = cookieString.split(";"); - - /** @type {*} */ - let cookieObject = {}; - - cookieSplitArray.forEach((keyValueString) => { - const [key, value] = keyValueString.split("="); - if (key && typeof key == "string") { - cookieObject[key.replace(/^ +| +$/, "")] = value && typeof value == "string" ? value.replace(/^ +| +$/, "") : null; - } - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - - return cookieObject; -}; - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const http = require("http"); + +/** + * Parse request cookies + * ============================================================================== + * + * @description This function takes in a request object and returns the cookies as a JS object + * + * @async + * + * @param {object} params - main params object + * @param {http.IncomingMessage} params.request - HTTPS request object + * + * @returns {* | null} + */ +module.exports = function ({ request }) { + /** + * Check inputs + * + * @description Check inputs + */ + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** @type {string | undefined} */ + const cookieString = request.headers.cookie; + + if (!cookieString || typeof cookieString !== "string") { + return null; + } + + /** @type {string[]} */ + const cookieSplitArray = cookieString.split(";"); + + /** @type {*} */ + let cookieObject = {}; + + cookieSplitArray.forEach((keyValueString) => { + const [key, value] = keyValueString.split("="); + if (key && typeof key == "string") { + cookieObject[key.replace(/^ +| +$/, "")] = value && typeof value == "string" ? value.replace(/^ +| +$/, "") : null; + } + }); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + + return cookieObject; +}; + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// diff --git a/utils/functions/sanitizeSql.js b/utils/functions/sanitizeSql.js index a000f16..4a3583a 100644 --- a/utils/functions/sanitizeSql.js +++ b/utils/functions/sanitizeSql.js @@ -1,184 +1,184 @@ -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -/** - * Sanitize SQL function - * ============================================================================== - * @description this function takes in a text(or number) or object or array or - * boolean and returns a sanitized version of the same input. - * - * @param {string|number|object|boolean} input - Text or number or object or boolean - * @param {boolean?} spaces - Allow spaces? - * - * @returns {string|number|object|boolean} - */ -function sanitizeSql(input, spaces) { - /** - * Initial Checks - * - * @description Initial Checks - */ - if (!input) return ""; - if (typeof input == "number" || typeof input == "boolean") return input; - if (typeof input == "string" && !input?.toString()?.match(/./)) return ""; - - if (typeof input == "object" && !Array.isArray(input)) { - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - const newObject = sanitizeObjects(input, spaces); - return newObject; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } else if (typeof input == "object" && Array.isArray(input)) { - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - const newArray = sanitizeArrays(input, spaces); - return newArray; - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - /** - * Declare variables - * - * @description Declare "results" variable - */ - let finalText = input; - - if (spaces) { - } else { - finalText = input - .toString() - .replace(/\n|\r|\n\r|\r\n/g, "") - .replace(/ /g, ""); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - const escapeRegex = /select |insert |drop |delete |alter |create |exec | union | or | like | concat|LOAD_FILE|ASCII| COLLATE | HAVING | information_schema|DECLARE |\#|WAITFOR |delay |BENCHMARK |\/\*.*\*\//gi; - - finalText = finalText - .replace(/(? { - const value = objectUpdated[key]; - - if (!value) { - delete objectUpdated[key]; - return; - } - - if (typeof value == "string" || typeof value == "number") { - objectUpdated[key] = sanitizeSql(value, spaces); - } else if (typeof value == "object" && !Array.isArray(value)) { - objectUpdated[key] = sanitizeObjects(value, spaces); - } else if (typeof value == "object" && Array.isArray(value)) { - objectUpdated[key] = sanitizeArrays(value, spaces); - } - }); - - return objectUpdated; -} - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -/** - * Sanitize Objects Function - * ============================================================================== - * @description Sanitize objects in the form { key: "value" } - * - * @param {string[]|number[]|object[]} array - Database Full Name - * @param {boolean?} spaces - Allow spaces - * - * @returns {string[]|number[]|object[]} - */ -function sanitizeArrays(array, spaces) { - let arrayUpdated = [...array]; - - arrayUpdated.forEach((item, index) => { - const value = item; - - if (!value) { - arrayUpdated.splice(index, 1); - return; - } - - if (typeof item == "string" || typeof item == "number") { - arrayUpdated[index] = sanitizeSql(value, spaces); - } else if (typeof item == "object" && !Array.isArray(value)) { - arrayUpdated[index] = sanitizeObjects(value, spaces); - } else if (typeof item == "object" && Array.isArray(value)) { - arrayUpdated[index] = sanitizeArrays(item, spaces); - } - }); - - return arrayUpdated; -} - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -module.exports = sanitizeSql; +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Sanitize SQL function + * ============================================================================== + * @description this function takes in a text(or number) or object or array or + * boolean and returns a sanitized version of the same input. + * + * @param {string|number|object|boolean} input - Text or number or object or boolean + * @param {boolean?} spaces - Allow spaces? + * + * @returns {string|number|object|boolean} + */ +function sanitizeSql(input, spaces) { + /** + * Initial Checks + * + * @description Initial Checks + */ + if (!input) return ""; + if (typeof input == "number" || typeof input == "boolean") return input; + if (typeof input == "string" && !input?.toString()?.match(/./)) return ""; + + if (typeof input == "object" && !Array.isArray(input)) { + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + const newObject = sanitizeObjects(input, spaces); + return newObject; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } else if (typeof input == "object" && Array.isArray(input)) { + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + const newArray = sanitizeArrays(input, spaces); + return newArray; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + /** + * Declare variables + * + * @description Declare "results" variable + */ + let finalText = input; + + if (spaces) { + } else { + finalText = input + .toString() + .replace(/\n|\r|\n\r|\r\n/g, "") + .replace(/ /g, ""); + } + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + + const escapeRegex = /select |insert |drop |delete |alter |create |exec | union | or | like | concat|LOAD_FILE|ASCII| COLLATE | HAVING | information_schema|DECLARE |\#|WAITFOR |delay |BENCHMARK |\/\*.*\*\//gi; + + finalText = finalText + .replace(/(? { + const value = objectUpdated[key]; + + if (!value) { + delete objectUpdated[key]; + return; + } + + if (typeof value == "string" || typeof value == "number") { + objectUpdated[key] = sanitizeSql(value, spaces); + } else if (typeof value == "object" && !Array.isArray(value)) { + objectUpdated[key] = sanitizeObjects(value, spaces); + } else if (typeof value == "object" && Array.isArray(value)) { + objectUpdated[key] = sanitizeArrays(value, spaces); + } + }); + + return objectUpdated; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Sanitize Objects Function + * ============================================================================== + * @description Sanitize objects in the form { key: "value" } + * + * @param {string[]|number[]|object[]} array - Database Full Name + * @param {boolean?} spaces - Allow spaces + * + * @returns {string[]|number[]|object[]} + */ +function sanitizeArrays(array, spaces) { + let arrayUpdated = [...array]; + + arrayUpdated.forEach((item, index) => { + const value = item; + + if (!value) { + arrayUpdated.splice(index, 1); + return; + } + + if (typeof item == "string" || typeof item == "number") { + arrayUpdated[index] = sanitizeSql(value, spaces); + } else if (typeof item == "object" && !Array.isArray(value)) { + arrayUpdated[index] = sanitizeObjects(value, spaces); + } else if (typeof item == "object" && Array.isArray(value)) { + arrayUpdated[index] = sanitizeArrays(item, spaces); + } + }); + + return arrayUpdated; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +module.exports = sanitizeSql; diff --git a/utils/get-schema.js b/utils/get-schema.js index 8e9a877..3cd32b4 100644 --- a/utils/get-schema.js +++ b/utils/get-schema.js @@ -1,89 +1,89 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const https = require("https"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {Object} GetSchemaReturn - * @property {boolean} success - Did the function run successfully? - * @property {import("../types/database-schema.td").DSQL_DatabaseSchemaType[] | import("../types/database-schema.td").DSQL_DatabaseSchemaType | null} payload - Response payload - */ - -/** - * Make a get request to Datasquirel API - * ============================================================================== - * @async - * - * @param {Object} params - Single object passed - * @param {string} params.key - `FULL ACCESS` API Key - * @param {string} [params.database] - The database schema to get - * - * @returns { Promise } - Return Object - */ -async function getSchema({ key, database }) { - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - const httpResponse = await new Promise((resolve, reject) => { - https - .request( - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: key, - }, - port: 443, - hostname: "datasquirel.com", - path: "/api/query/get-schema" + (database ? `?database=${database}` : ""), - }, - - /** - * 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; -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = getSchema; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const https = require("https"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {Object} GetSchemaReturn + * @property {boolean} success - Did the function run successfully? + * @property {import("../types/database-schema.td").DSQL_DatabaseSchemaType[] | import("../types/database-schema.td").DSQL_DatabaseSchemaType | null} payload - Response payload + */ + +/** + * Make a get request to Datasquirel API + * ============================================================================== + * @async + * + * @param {Object} params - Single object passed + * @param {string} params.key - `FULL ACCESS` API Key + * @param {string} [params.database] - The database schema to get + * + * @returns { Promise } - Return Object + */ +async function getSchema({ key, database }) { + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + const httpResponse = await new Promise((resolve, reject) => { + https + .request( + { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: key, + }, + port: 443, + hostname: "datasquirel.com", + path: "/api/query/get-schema" + (database ? `?database=${database}` : ""), + }, + + /** + * 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; +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = getSchema; diff --git a/utils/get.js b/utils/get.js index 7e214bb..85c83e0 100644 --- a/utils/get.js +++ b/utils/get.js @@ -1,134 +1,134 @@ -// @ts-check - -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const https = require("https"); -const path = require("path"); -const fs = require("fs"); -const localGet = require("../engine/query/get"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {Object} GetReturn - * @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 {string} [params.key] - API Key - * @param {string} [params.db] - Database Name - * @param {string} params.query - SQL Query - * @param {string[]} [params.queryValues] - An array of query values if using "?" placeholders - * @param {string} [params.tableName] - Name of the table to query - * - * @returns { Promise } - Return Object - */ -async function get({ key, db, query, queryValues, 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 localGet({ - dbSchema: dbSchema, - options: { - query: query, - queryValues: queryValues, - tableName: tableName, - }, - }); - } - - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - const httpResponse = await new Promise((resolve, reject) => { - let path = `/api/query/get?db=${db}&query=${query - .replace(/\n|\r|\n\r/g, "") - .replace(/ {2,}/g, " ") - .replace(/ /g, "+")}`; - - if (queryValues) { - path += `&queryValues=${JSON.stringify(queryValues)}${tableName ? `&tableName=${tableName}` : ""}`; - } - - https - .request( - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: key, - }, - port: 443, - hostname: "datasquirel.com", - path: path, - }, - - /** - * 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; -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = get; +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const https = require("https"); +const path = require("path"); +const fs = require("fs"); +const localGet = require("../engine/query/get"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {Object} GetReturn + * @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 {string} [params.key] - API Key + * @param {string} [params.db] - Database Name + * @param {string} params.query - SQL Query + * @param {string[]} [params.queryValues] - An array of query values if using "?" placeholders + * @param {string} [params.tableName] - Name of the table to query + * + * @returns { Promise } - Return Object + */ +async function get({ key, db, query, queryValues, 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 localGet({ + dbSchema: dbSchema, + options: { + query: query, + queryValues: queryValues, + tableName: tableName, + }, + }); + } + + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + const httpResponse = await new Promise((resolve, reject) => { + let path = `/api/query/get?db=${db}&query=${query + .replace(/\n|\r|\n\r/g, "") + .replace(/ {2,}/g, " ") + .replace(/ /g, "+")}`; + + if (queryValues) { + path += `&queryValues=${JSON.stringify(queryValues)}${tableName ? `&tableName=${tableName}` : ""}`; + } + + https + .request( + { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: key, + }, + port: 443, + hostname: "datasquirel.com", + path: path, + }, + + /** + * 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; +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = get; diff --git a/utils/post.js b/utils/post.js index b6806f9..eb0471d 100644 --- a/utils/post.js +++ b/utils/post.js @@ -1,181 +1,181 @@ -// @ts-check - -/** - * Imports - */ -const https = require("https"); -const path = require("path"); -const fs = require("fs"); -const localPost = require("../engine/query/post"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {Object} PostReturn - * @property {boolean} success - Did the function run successfully? - * @property {(Object[]|string)} [payload=[]] - The Y Coordinate - */ - -/** - * @typedef {object} PostDataPayload - * @property {"insert" | "update" | "delete"} action - The target action to take - * @property {string} table - Table name(slug) eg "blog_posts" - * @property {object} [data] - Table insert payload object => This must have keys that match - * table fields - * @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 {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? - */ - -/** - * Make a post request to Datasquirel API - * ============================================================================== - * @async - * - * @param {Object} params - Single object passed - * @param {string} [params.key] - FULL ACCESS API Key - * @param {string} [params.database] - Database Name - * @param {PostDataPayload | string} params.query - SQL query String or Request Object - * @param {any[]} [params.queryValues] - Query Values if using "?" placeholders - * @param {string} [params.tableName] - Name of the table to query - * - * @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 - * - * @description make a request to datasquirel.com - */ - const httpResponse = await new Promise((resolve, reject) => { - const reqPayloadString = JSON.stringify({ - query, - queryValues, - database, - tableName: tableName ? tableName : null, - }).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/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); - 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; -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = post; +// @ts-check + +/** + * Imports + */ +const https = require("https"); +const path = require("path"); +const fs = require("fs"); +const localPost = require("../engine/query/post"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {Object} PostReturn + * @property {boolean} success - Did the function run successfully? + * @property {(Object[]|string)} [payload=[]] - The Y Coordinate + */ + +/** + * @typedef {object} PostDataPayload + * @property {"insert" | "update" | "delete"} action - The target action to take + * @property {string} table - Table name(slug) eg "blog_posts" + * @property {object} [data] - Table insert payload object => This must have keys that match + * table fields + * @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 {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? + */ + +/** + * Make a post request to Datasquirel API + * ============================================================================== + * @async + * + * @param {Object} params - Single object passed + * @param {string} [params.key] - FULL ACCESS API Key + * @param {string} [params.database] - Database Name + * @param {PostDataPayload | string} params.query - SQL query String or Request Object + * @param {any[]} [params.queryValues] - Query Values if using "?" placeholders + * @param {string} [params.tableName] - Name of the table to query + * + * @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 + * + * @description make a request to datasquirel.com + */ + const httpResponse = await new Promise((resolve, reject) => { + const reqPayloadString = JSON.stringify({ + query, + queryValues, + database, + tableName: tableName ? tableName : null, + }).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/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); + 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; +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = post; diff --git a/utils/upload-file.js b/utils/upload-file.js index 1ba01dd..f9634f2 100644 --- a/utils/upload-file.js +++ b/utils/upload-file.js @@ -1,115 +1,115 @@ -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const https = require("https"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {Object} FunctionReturn - * @property {boolean} success - Did the function run successfully? - * @property {{ - * urlPath: string, - * }} payload - Payload containing the url for the image and its thumbnail - * @property {string} [msg] - An optional message - */ - -/** - * ============================================================================== - * Main Function - * ============================================================================== - * @async - * - * @param {Object} params - Single Param object containing params - * @param {String} params.key - *FULL ACCESS API Key - * @param {{ - * fileData: string, - * fileName: string, - * mimeType?: string, - * folder?: string, - * isPrivate?: boolean, - * }} params.payload - Image Data Eg. - * - * @returns { Promise } - Return Object - */ -async function uploadImage({ key, payload }) { - try { - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - const httpResponse = await new Promise((resolve, reject) => { - const reqPayload = JSON.stringify(payload); - - 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/add-file`, - }, - - /** - * 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); - }); - } - ); - - httpsRequest.write(reqPayload); - httpsRequest.end(); - }); - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - return httpResponse; - } catch (/** @type {*} */ error) { - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - console.log("Error in uploading file: ", error.message); - - return { - success: false, - payload: null, - msg: error.message, - }; - } -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = uploadImage; +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const https = require("https"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {Object} FunctionReturn + * @property {boolean} success - Did the function run successfully? + * @property {{ + * urlPath: string, + * }} payload - Payload containing the url for the image and its thumbnail + * @property {string} [msg] - An optional message + */ + +/** + * ============================================================================== + * Main Function + * ============================================================================== + * @async + * + * @param {Object} params - Single Param object containing params + * @param {String} params.key - *FULL ACCESS API Key + * @param {{ + * fileData: string, + * fileName: string, + * mimeType?: string, + * folder?: string, + * isPrivate?: boolean, + * }} params.payload - Image Data Eg. + * + * @returns { Promise } - Return Object + */ +async function uploadImage({ key, payload }) { + try { + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + const httpResponse = await new Promise((resolve, reject) => { + const reqPayload = JSON.stringify(payload); + + 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/add-file`, + }, + + /** + * 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); + }); + } + ); + + httpsRequest.write(reqPayload); + httpsRequest.end(); + }); + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + return httpResponse; + } catch (/** @type {*} */ error) { + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + console.log("Error in uploading file: ", error.message); + + return { + success: false, + payload: null, + msg: error.message, + }; + } +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = uploadImage; diff --git a/utils/upload-image.js b/utils/upload-image.js index 25964ca..2c4278d 100644 --- a/utils/upload-image.js +++ b/utils/upload-image.js @@ -1,117 +1,117 @@ -/** - * ============================================================================== - * Imports - * ============================================================================== - */ -const https = require("https"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * @typedef {Object} FunctionReturn - * @property {boolean} success - Did the function run successfully? - * @property {{ - * urlPath: string, - * urlThumbnailPath: string - * }} payload - Payload containing the url for the image and its thumbnail - * @property {string} [msg] - An optional message - */ - -/** - * ============================================================================== - * Main Function - * ============================================================================== - * @async - * - * @param {Object} params - Single Param object containing params - * @param {String} params.key - *FULL ACCESS API Key - * @param {{ - * imageData: string, - * imageName: string, - * mimeType?: string, - * thumbnailSize?: number, - * folder?: string, - * isPrivate?: boolean, - * }} params.payload - Image Data Eg. - * - * @returns { Promise } - Return Object - */ -async function uploadImage({ key, payload }) { - try { - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - const httpResponse = await new Promise((resolve, reject) => { - const reqPayload = JSON.stringify(payload); - - 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/add-image`, - }, - - /** - * 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); - }); - } - ); - - httpsRequest.write(reqPayload); - httpsRequest.end(); - }); - - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - return httpResponse; - } catch (/** @type {*} */ error) { - /** ********************************************** */ - /** ********************************************** */ - /** ********************************************** */ - - console.log("Error in uploading image: ", error.message); - - return { - success: false, - payload: null, - msg: error.message, - }; - } -} - -/** ********************************************** */ -/** ********************************************** */ -/** ********************************************** */ - -module.exports = uploadImage; +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const https = require("https"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {Object} FunctionReturn + * @property {boolean} success - Did the function run successfully? + * @property {{ + * urlPath: string, + * urlThumbnailPath: string + * }} payload - Payload containing the url for the image and its thumbnail + * @property {string} [msg] - An optional message + */ + +/** + * ============================================================================== + * Main Function + * ============================================================================== + * @async + * + * @param {Object} params - Single Param object containing params + * @param {String} params.key - *FULL ACCESS API Key + * @param {{ + * imageData: string, + * imageName: string, + * mimeType?: string, + * thumbnailSize?: number, + * folder?: string, + * isPrivate?: boolean, + * }} params.payload - Image Data Eg. + * + * @returns { Promise } - Return Object + */ +async function uploadImage({ key, payload }) { + try { + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + const httpResponse = await new Promise((resolve, reject) => { + const reqPayload = JSON.stringify(payload); + + 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/add-image`, + }, + + /** + * 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); + }); + } + ); + + httpsRequest.write(reqPayload); + httpsRequest.end(); + }); + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + return httpResponse; + } catch (/** @type {*} */ error) { + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + console.log("Error in uploading image: ", error.message); + + return { + success: false, + payload: null, + msg: error.message, + }; + } +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = uploadImage;