From b047d6557c6fa5a309b8659a800358e761174d3b Mon Sep 17 00:00:00 2001 From: Benjamin Toby Date: Wed, 27 Nov 2024 11:02:03 +0100 Subject: [PATCH] Major refactoring: Add user id to API routes --- README.md | 8 +++++++ .../query/update-api-schema-from-local-db.js | 4 ++-- functions/sql/sql-generator.js | 6 +++++- package-shared/functions/backend/api-cred.js | 5 ++++- package-shared/types/index.d.ts | 11 ++++++++++ package-shared/utils/grab-host-names.js | 2 ++ package.json | 2 +- users/add-user.js | 21 ++++++++++++------- users/get-user.js | 10 ++++++--- users/login-user.js | 9 ++++++-- users/reauth-user.js | 9 ++++++-- users/send-email-code.js | 9 ++++++-- users/social/github-auth.js | 9 ++++++-- users/social/google-auth.js | 9 ++++++-- users/update-user.js | 10 ++++++--- utils/delete-file.js | 12 +++++++---- utils/get-schema.js | 10 +++++---- utils/get.js | 18 +++++++++++++--- utils/post.js | 7 +++++-- utils/upload-file.js | 12 +++++++---- utils/upload-image.js | 10 ++++++--- 21 files changed, 144 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index c73ef97..c530b74 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,12 @@ 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 + user_id: 129, // Your User Id: check settings page }); ``` +> NOTE: You can skip the `user_id` parameter by adding an environment variable named `DSQL_API_USER_ID` + Datasquirel uses all conventional SQL query commands. However you can only use the `SELECT` command when using a readonly API key. ### Post Data @@ -63,6 +66,7 @@ const postData = await datasquirel.post({ user_last_name: "Doe", }, table: "users", + user_id: 271, }, }); ``` @@ -75,6 +79,7 @@ const datasquirel = require("@moduletrace/datasquirel"); const postData = await datasquirel.post({ key: process.env.FULL_ACCESS_API_KEY, payload: "SELECT * FROM blog_posts WHERE user_id='as09d7nasd90'", + user_id: 271, }); ``` @@ -90,6 +95,7 @@ const postData = await datasquirel.post({ condition: `WHERE user_id='21adwei9jewr' AND type='buyers'`, table: "users", }, + user_id: 271, }); ``` @@ -110,6 +116,7 @@ const postData = await datasquirel.post({ last_name: "Spencer", }, }, + user_id: 271, }); ``` @@ -128,6 +135,7 @@ const postData = await datasquirel.uploadImage({ mimeType: "jpg", // optional thumbnailSize: 120, // optional === This measurement is in pixels(px) }, + user_id: 271, }); ``` diff --git a/engine/query/update-api-schema-from-local-db.js b/engine/query/update-api-schema-from-local-db.js index 4f09243..c5267a0 100644 --- a/engine/query/update-api-schema-from-local-db.js +++ b/engine/query/update-api-schema-from-local-db.js @@ -39,7 +39,7 @@ async function updateApiSchemaFromLocalDb() { const key = process.env.DSQL_KEY || ""; const dbSchema = JSON.parse(fs.readFileSync(dbSchemaPath, "utf8")); - const { host, port, scheme } = grabHostNames(); + const { host, port, scheme, user_id } = grabHostNames(); /** * Make https request @@ -79,7 +79,7 @@ async function updateApiSchemaFromLocalDb() { }, port, hostname: host, - path: `/api/query/update-schema-from-single-database`, + path: `/api/query/${user_id}/update-schema-from-single-database`, }, /** diff --git a/functions/sql/sql-generator.js b/functions/sql/sql-generator.js index 8e018f1..8def027 100644 --- a/functions/sql/sql-generator.js +++ b/functions/sql/sql-generator.js @@ -178,7 +178,11 @@ function sqlGenerator({ tableName, genObject }) { } if (genObject.order) - queryString += ` ORDER BY ${genObject.order.field} ${genObject.order.strategy}`; + queryString += ` ORDER BY ${ + genObject.join + ? `${tableName}.${genObject.order.field}` + : genObject.order.field + } ${genObject.order.strategy}`; if (genObject.limit) queryString += ` LIMIT ${genObject.limit}`; return { diff --git a/package-shared/functions/backend/api-cred.js b/package-shared/functions/backend/api-cred.js index 4286240..ebfa7bb 100644 --- a/package-shared/functions/backend/api-cred.js +++ b/package-shared/functions/backend/api-cred.js @@ -4,8 +4,9 @@ const fs = require("fs"); const decrypt = require("./decrypt"); /** @type {import("../../types").CheckApiCredentialsFn} */ -const grabApiCred = ({ key, database, table }) => { +const grabApiCred = ({ key, database, table, user_id }) => { if (!key) return null; + if (!user_id) return null; try { const allowedKeysPath = process.env.DSQL_API_KEYS_PATH; @@ -22,6 +23,8 @@ const grabApiCred = ({ key, database, table }) => { `${allowedKeysPath}/${ApiObject.sign}` ); + if (String(ApiObject.user_id) !== String(user_id)) return null; + if (!isApiKeyValid) return null; if (!ApiObject.target_database) return ApiObject; if (!database && ApiObject.target_database) return null; diff --git a/package-shared/types/index.d.ts b/package-shared/types/index.d.ts index 544dda3..d6adf78 100644 --- a/package-shared/types/index.d.ts +++ b/package-shared/types/index.d.ts @@ -335,6 +335,7 @@ export interface GetSchemaRequestQuery { database?: string; table?: string; field?: string; + user_id?: string | number; } export interface GetSchemaAPICredentialsParam { @@ -1095,6 +1096,7 @@ export type CheckApiCredentialsFnParam = { key?: string; database?: string; table?: string; + user_id?: string | number; }; export type FetchApiFn = ( @@ -1218,3 +1220,12 @@ export type SqlGeneratorFn = (Param0: { values: string[]; } | undefined; + +export type ApiConnectBody = { + url: string; + key: string; + database: DSQL_MYSQL_user_databases_Type; + dbSchema: DSQL_DatabaseSchemaType; + type: "pull" | "push"; + user_id?: string | number; +}; diff --git a/package-shared/utils/grab-host-names.js b/package-shared/utils/grab-host-names.js index 3baff49..ce98682 100644 --- a/package-shared/utils/grab-host-names.js +++ b/package-shared/utils/grab-host-names.js @@ -8,6 +8,7 @@ const http = require("http"); * @property {string} host * @property {number | string} port * @property {typeof http | typeof https} scheme + * @property {string | number} user_id */ /** @@ -29,6 +30,7 @@ function grabHostNames() { host: remoteHost || localHost || "datasquirel.com", port: remoteHostPort || localHostPort || 443, scheme: scheme?.match(/^http$/i) ? http : https, + user_id: String(process.env.DSQL_API_USER_ID || 0), }; } diff --git a/package.json b/package.json index e7caf36..38741ac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@moduletrace/datasquirel", - "version": "2.7.3", + "version": "2.7.4", "description": "Cloud-based SQL data management tool", "main": "index.js", "bin": { diff --git a/users/add-user.js b/users/add-user.js index 5a80301..ea2a129 100644 --- a/users/add-user.js +++ b/users/add-user.js @@ -12,12 +12,13 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * ============================================================================== * @async * - * @param {object} props - Single object passed - * @param {string} props.key - FULL ACCESS API Key - * @param {string} props.database - Database Name - * @param {import("../package-shared/types").UserDataPayload} props.payload - User Data Payload - * @param {string} props.encryptionKey - * @param {string} [props.encryptionSalt] + * @param {object} param - Single object passed + * @param {string} param.key - FULL ACCESS API Key + * @param {string} param.database - Database Name + * @param {import("../package-shared/types").UserDataPayload} param.payload - User Data Payload + * @param {string} param.encryptionKey + * @param {string} [param.encryptionSalt] + * @param {boolean} [param.user_id] - User ID * * @returns { Promise } */ @@ -27,6 +28,7 @@ async function addUser({ database, encryptionKey, encryptionSalt, + user_id, }) { /** * Check for local DB settings @@ -43,7 +45,8 @@ async function addUser({ DSQL_FULL_SYNC, } = process.env; - const { host, port, scheme } = grabHostNames(); + const grabedHostNames = grabHostNames(); + const { host, port, scheme } = grabedHostNames; if ( DSQL_HOST?.match(/./) && @@ -97,7 +100,9 @@ async function addUser({ }, port, hostname: host, - path: `/api/user/add-user`, + path: `/api/user/${ + user_id || grabedHostNames.user_id + }/add-user`, }, /** diff --git a/users/get-user.js b/users/get-user.js index aa2c2bf..ade7e99 100644 --- a/users/get-user.js +++ b/users/get-user.js @@ -30,10 +30,11 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * @param {String} params.database - Target Database * @param {number} params.userId - user id * @param {string[]} [params.fields] - fields to select + * @param {boolean} [params.user_id] - User ID * * @returns { Promise} */ -async function getUser({ key, userId, database, fields }) { +async function getUser({ key, userId, database, fields, user_id }) { /** * Initialize */ @@ -63,7 +64,8 @@ async function getUser({ key, userId, database, fields }) { fields: [...new Set(updatedFields)], }); - const { host, port, scheme } = grabHostNames(); + const grabedHostNames = grabHostNames(); + const { host, port, scheme } = grabedHostNames; /** * Check for local DB settings @@ -125,7 +127,9 @@ async function getUser({ key, userId, database, fields }) { }, port, hostname: host, - path: `/api/user/get-user`, + path: `/api/user/${ + user_id || grabedHostNames.user_id + }/get-user`, }, /** diff --git a/users/login-user.js b/users/login-user.js index 4135ce2..9f70108 100644 --- a/users/login-user.js +++ b/users/login-user.js @@ -41,6 +41,7 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * @param {string} [params.email_login_code] - Email login code * @param {string} [params.temp_code_field] - Database table field name for temporary code * @param {boolean} [params.token] - Send access key as part of response body? + * @param {boolean} [params.user_id] - User ID * * @returns { Promise} */ @@ -56,8 +57,10 @@ async function loginUser({ email_login_code, temp_code_field, token, + user_id, }) { - const { host, port, scheme } = grabHostNames(); + const grabedHostNames = grabHostNames(); + const { host, port, scheme } = grabedHostNames; const defaultTempLoginFieldName = "temp_login_code"; const emailLoginTempCodeFieldName = email_login @@ -183,7 +186,9 @@ async function loginUser({ }, port, hostname: host, - path: `/api/user/login-user`, + path: `/api/user/${ + user_id || grabedHostNames.user_id + }/login-user`, }, /** diff --git a/users/reauth-user.js b/users/reauth-user.js index 9e08448..3d3ff84 100644 --- a/users/reauth-user.js +++ b/users/reauth-user.js @@ -38,6 +38,7 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * @param {String} params.encryptionSalt - Encryption Salt * @param {string[]} [params.additionalFields] - Additional Fields to be added to the user object * @param {string} [params.token] - access token to use instead of getting from cookie header + * @param {boolean} [params.user_id] - User ID * * @returns { Promise } */ @@ -51,13 +52,15 @@ async function reauthUser({ encryptionSalt, additionalFields, token, + user_id, }) { /** * Check Encryption Keys * * @description Check Encryption Keys */ - const { host, port, scheme } = grabHostNames(); + const grabedHostNames = grabHostNames(); + const { host, port, scheme } = grabedHostNames; const existingUser = userAuth({ database, @@ -146,7 +149,9 @@ async function reauthUser({ }, port, hostname: host, - path: `/api/user/reauth-user`, + path: `/api/user/${ + user_id || grabedHostNames.user_id + }/reauth-user`, }, /** diff --git a/users/send-email-code.js b/users/send-email-code.js index 81baf33..6e7049c 100644 --- a/users/send-email-code.js +++ b/users/send-email-code.js @@ -39,6 +39,7 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * @param {string} [params.mail_password] * @param {number} [params.mail_port] * @param {string} [params.sender] + * @param {boolean} [params.user_id] - User ID * * @returns { Promise} */ @@ -54,8 +55,10 @@ async function sendEmailCode({ mail_username, mail_port, sender, + user_id, }) { - const { host, port, scheme } = grabHostNames(); + const grabedHostNames = grabHostNames(); + const { host, port, scheme } = grabedHostNames; const defaultTempLoginFieldName = "temp_login_code"; const emailLoginTempCodeFieldName = temp_code_field @@ -176,7 +179,9 @@ async function sendEmailCode({ }, port, hostname: host, - path: `/api/user/send-email-code`, + path: `/api/user/${ + user_id || grabedHostNames.user_id + }/send-email-code`, }, /** diff --git a/users/social/github-auth.js b/users/social/github-auth.js index 26f33d8..7f7fffb 100644 --- a/users/social/github-auth.js +++ b/users/social/github-auth.js @@ -45,6 +45,7 @@ const grabHostNames = require("../../package-shared/utils/grab-host-names"); * @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 + * @param {boolean} [params.user_id] - User ID * * @returns { Promise } */ @@ -59,13 +60,15 @@ async function githubAuth({ encryptionKey, encryptionSalt, additionalFields, + user_id, }) { /** * Check inputs * * @description Check inputs */ - const { host, port, scheme } = grabHostNames(); + const grabedHostNames = grabHostNames(); + const { host, port, scheme } = grabedHostNames; if (!key || key?.match(/ /)) { return { @@ -205,7 +208,9 @@ async function githubAuth({ }, port, hostname: host, - path: `/api/user/github-login`, + path: `/api/user/${ + user_id || grabedHostNames.user_id + }/github-login`, }, /** diff --git a/users/social/google-auth.js b/users/social/google-auth.js index 8aad757..8fee0c6 100644 --- a/users/social/google-auth.js +++ b/users/social/google-auth.js @@ -43,6 +43,7 @@ const grabHostNames = require("../../package-shared/utils/grab-host-names"); * @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 + * @param {boolean} [params.user_id] - User ID * * @returns { Promise } */ @@ -55,8 +56,10 @@ async function googleAuth({ encryptionKey, encryptionSalt, additionalFields, + user_id, }) { - const { host, port, scheme } = grabHostNames(); + const grabedHostNames = grabHostNames(); + const { host, port, scheme } = grabedHostNames; /** * Check inputs @@ -201,7 +204,9 @@ async function googleAuth({ }, port, hostname: host, - path: `/api/user/google-login`, + path: `/api/user/${ + user_id || grabedHostNames.user_id + }/google-login`, }, /** diff --git a/users/update-user.js b/users/update-user.js index 4cfa1d1..b522d6b 100644 --- a/users/update-user.js +++ b/users/update-user.js @@ -15,10 +15,11 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * @param {String} params.key - API Key * @param {String} params.database - Target Database * @param {{ id: number } & Object.} params.payload - User Object: ID is required + * @param {boolean} [params.user_id] - User ID * * @returns { Promise} */ -async function updateUser({ key, payload, database }) { +async function updateUser({ key, payload, database, user_id }) { /** * Check for local DB settings * @@ -34,7 +35,8 @@ async function updateUser({ key, payload, database }) { DSQL_FULL_SYNC, } = process.env; - const { host, port, scheme } = grabHostNames(); + const grabedHostNames = grabHostNames(); + const { host, port, scheme } = grabedHostNames; if ( DSQL_HOST?.match(/./) && @@ -85,7 +87,9 @@ async function updateUser({ key, payload, database }) { }, port, hostname: host, - path: `/api/user/update-user`, + path: `/api/user/${ + user_id || grabedHostNames.user_id + }/update-user`, }, /** diff --git a/utils/delete-file.js b/utils/delete-file.js index 46fdac2..a56cb04 100644 --- a/utils/delete-file.js +++ b/utils/delete-file.js @@ -21,11 +21,13 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * @param {Object} params - Single Param object containing params * @param {String} params.key - *FULL ACCESS API Key * @param { string } params.url - File URL + * @param { string | number } [params.user_id] * * @returns { Promise } - Image Url */ -async function uploadImage({ key, url }) { - const { host, port, scheme } = grabHostNames(); +async function deleteFile({ key, url, user_id }) { + const grabedHostNames = grabHostNames(); + const { host, port, scheme } = grabedHostNames; try { /** @@ -49,7 +51,9 @@ async function uploadImage({ key, url }) { }, port, hostname: host, - path: `/api/query/delete-file`, + path: `/api/query/${ + user_id || grabedHostNames.user_id + }/delete-file`, }, /** @@ -90,4 +94,4 @@ async function uploadImage({ key, url }) { } } -module.exports = uploadImage; +module.exports = deleteFile; diff --git a/utils/get-schema.js b/utils/get-schema.js index a54585f..59b568e 100644 --- a/utils/get-schema.js +++ b/utils/get-schema.js @@ -16,8 +16,9 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * * @returns { Promise } - Return Object */ -async function getSchema({ key, database, field, table }) { - const { host, port, scheme } = grabHostNames(); +async function getSchema({ key, database, field, table, user_id }) { + const grabedHostNames = grabHostNames(); + const { host, port, scheme } = grabedHostNames; /** * Make https request @@ -48,8 +49,9 @@ async function getSchema({ key, database, field, table }) { port, hostname: host, path: - "/api/query/get-schema" + - (query?.match(/./) ? `?${query}` : ""), + `/api/query/${ + user_id || grabedHostNames.user_id + }/get-schema` + (query?.match(/./) ? `?${query}` : ""), }, /** diff --git a/utils/get.js b/utils/get.js index d00aac2..392024a 100644 --- a/utils/get.js +++ b/utils/get.js @@ -20,11 +20,21 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * @param {string[]} [params.queryValues] - An array of query values if using "?" placeholders * @param {string} [params.tableName] - Name of the table to query * @param {boolean} [params.useLocal] - Whether to use a remote database instead of API + * @param {boolean} [params.user_id] - User ID * * @returns { Promise } - Return Object */ -async function get({ key, db, query, queryValues, tableName, useLocal }) { - const { host, port, scheme } = grabHostNames(); +async function get({ + key, + db, + query, + queryValues, + tableName, + useLocal, + user_id, +}) { + const grabedHostNames = grabHostNames(); + const { host, port, scheme } = grabedHostNames; /** * Check for local DB settings @@ -83,7 +93,9 @@ async function get({ key, db, query, queryValues, tableName, useLocal }) { const queryString = serializeQuery({ query: queryObject }); - let path = `/api/query/get${queryString}`; + let path = `/api/query/${ + user_id || grabedHostNames.user_id + }/get${queryString}`; /** @type {https.RequestOptions} */ const requestObject = { diff --git a/utils/post.js b/utils/post.js index f3794e7..929b452 100644 --- a/utils/post.js +++ b/utils/post.js @@ -16,6 +16,7 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * @param {any[]} [params.queryValues] - Query Values if using "?" placeholders * @param {string} [params.tableName] - Name of the table to query * @param {boolean} [params.useLocal] - Whether to use a remote database instead of API + * @param {boolean} [params.user_id] - User ID * * @returns { Promise } - Return Object */ @@ -26,8 +27,10 @@ async function post({ database, tableName, useLocal, + user_id, }) { - const { host, port, scheme } = grabHostNames(); + const grabedHostNames = grabHostNames(); + const { host, port, scheme } = grabedHostNames; /** * Check for local DB settings @@ -106,7 +109,7 @@ async function post({ }, port, hostname: host, - path: `/api/query/post`, + path: `/api/query/${user_id || grabedHostNames.user_id}/post`, }, /** diff --git a/utils/upload-file.js b/utils/upload-file.js index d7f475f..20eb695 100644 --- a/utils/upload-file.js +++ b/utils/upload-file.js @@ -24,13 +24,15 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * fileName: string, * mimeType?: string, * folder?: string, - * isPrivate?: boolean, + * isPrivate?: boolean * }} params.payload - Image Data Eg. + * @param {boolean} [params.user_id] - User ID * * @returns { Promise } - Return Object */ -async function uploadImage({ key, payload }) { - const { host, port, scheme } = grabHostNames(); +async function uploadImage({ key, payload, user_id }) { + const grabedHostNames = grabHostNames(); + const { host, port, scheme } = grabedHostNames; try { /** @@ -54,7 +56,9 @@ async function uploadImage({ key, payload }) { }, port, hostname: host, - path: `/api/query/add-file`, + path: `/api/query/${ + user_id || grabedHostNames.user_id + }/add-file`, }, /** diff --git a/utils/upload-image.js b/utils/upload-image.js index 847f17f..fc2cb7a 100644 --- a/utils/upload-image.js +++ b/utils/upload-image.js @@ -28,11 +28,13 @@ const grabHostNames = require("../package-shared/utils/grab-host-names"); * folder?: string, * isPrivate?: boolean, * }} params.payload - Image Data Eg. + * @param {boolean} [params.user_id] - User ID * * @returns { Promise } - Return Object */ -async function uploadImage({ key, payload }) { - const { host, port, scheme } = grabHostNames(); +async function uploadImage({ key, payload, user_id }) { + const grabedHostNames = grabHostNames(); + const { host, port, scheme } = grabedHostNames; try { /** @@ -56,7 +58,9 @@ async function uploadImage({ key, payload }) { }, port, hostname: host, - path: `/api/query/add-image`, + path: `/api/query/${ + user_id || grabedHostNames.user_id + }/add-image`, }, /**