From 081165b6f52344220a6a99b25fd48b78b41c99c0 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Wed, 26 Apr 2023 10:20:24 -0700 Subject: [PATCH] Resolve missing items from merge conflicts. --- .../breadcrumbs/breadcrumbs.component.jsx | 10 +- package-lock.json | 52 ++++ package.json | 3 + server.js | 7 + server/graphql-client/queries.js | 8 + server/opensearch/os-handler.js | 251 ++++++++++++++++++ yarn.lock | 5 + 7 files changed, 335 insertions(+), 1 deletion(-) create mode 100644 server/opensearch/os-handler.js diff --git a/client/src/components/breadcrumbs/breadcrumbs.component.jsx b/client/src/components/breadcrumbs/breadcrumbs.component.jsx index ee0d51bf6..ba2619c4e 100644 --- a/client/src/components/breadcrumbs/breadcrumbs.component.jsx +++ b/client/src/components/breadcrumbs/breadcrumbs.component.jsx @@ -7,7 +7,9 @@ import { createStructuredSelector } from "reselect"; import { selectBreadcrumbs } from "../../redux/application/application.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; import GlobalSearch from "../global-search/global-search.component"; +import GlobalSearchOs from "../global-search/global-search-os.component"; import "./breadcrumbs.styles.scss"; +import { useTreatments } from "@splitsoftware/splitio-react"; const mapStateToProps = createStructuredSelector({ breadcrumbs: selectBreadcrumbs, @@ -15,6 +17,12 @@ const mapStateToProps = createStructuredSelector({ }); export function BreadCrumbs({ breadcrumbs, bodyshop }) { + const { OpenSearch } = useTreatments( + ["OpenSearch"], + {}, + bodyshop && bodyshop.imexshopid + ); + return ( @@ -38,7 +46,7 @@ export function BreadCrumbs({ breadcrumbs, bodyshop }) { - + {OpenSearch.treatment === "on" ? : } ); diff --git a/package-lock.json b/package-lock.json index d9f7e3cfa..73a9108b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.1", "license": "UNLICENSED", "dependencies": { + "@opensearch-project/opensearch": "^2.2.1", "aws-sdk": "^2.1326.0", "axios": "^0.27.2", "bluebird": "^3.7.2", @@ -362,6 +363,22 @@ "node": ">=8.0" } }, + "node_modules/@opensearch-project/opensearch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@opensearch-project/opensearch/-/opensearch-2.2.1.tgz", + "integrity": "sha512-8zfQX1acL9eWG+ohIc9nJVT9LSqXCdbVEJs0rCPRtji3XF6ahzsiKmGNTeWLxCPDxWCjAIWq9t95xP3Y5Egi6Q==", + "dependencies": { + "aws4": "^1.11.0", + "debug": "^4.3.1", + "hpagent": "^1.2.0", + "ms": "^2.1.3", + "secure-json-parse": "^2.4.0" + }, + "engines": { + "node": ">=10", + "yarn": "^1.22.10" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -3066,6 +3083,14 @@ "node": ">=8" } }, + "node_modules/hpagent": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", + "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==", + "engines": { + "node": ">=14" + } + }, "node_modules/href-content": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/href-content/-/href-content-2.0.2.tgz", @@ -4972,6 +4997,11 @@ "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==", "license": "BSD-3-Clause" }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==" + }, "node_modules/semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", @@ -6580,6 +6610,18 @@ "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.3.8.tgz", "integrity": "sha512-T8TbSnGsxo6TDBJx/Sgv/BlVJL3tshxZP7Aq5R1mSnM5OcHY2dQaxLMu2+E8u3gN0MLOzdjurqN4ZRVuzQycOQ==" }, + "@opensearch-project/opensearch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@opensearch-project/opensearch/-/opensearch-2.2.1.tgz", + "integrity": "sha512-8zfQX1acL9eWG+ohIc9nJVT9LSqXCdbVEJs0rCPRtji3XF6ahzsiKmGNTeWLxCPDxWCjAIWq9t95xP3Y5Egi6Q==", + "requires": { + "aws4": "^1.11.0", + "debug": "^4.3.1", + "hpagent": "^1.2.0", + "ms": "^2.1.3", + "secure-json-parse": "^2.4.0" + } + }, "@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -8622,6 +8664,11 @@ "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==" }, + "hpagent": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", + "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==" + }, "href-content": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/href-content/-/href-content-2.0.2.tgz", @@ -10042,6 +10089,11 @@ "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz", "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==" }, + "secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==" + }, "semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", diff --git a/package.json b/package.json index 47f432c8f..e2896516b 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,10 @@ "start": "node server.js" }, "dependencies": { + "@aws-sdk/credential-provider-node": "^3.319.0", + "@opensearch-project/opensearch": "^2.2.1", "aws-sdk": "^2.1326.0", + "aws4": "^1.12.0", "axios": "^0.27.2", "bluebird": "^3.7.2", "body-parser": "^1.20.2", diff --git a/server.js b/server.js index 0a36f00b9..273676bb9 100644 --- a/server.js +++ b/server.js @@ -233,6 +233,13 @@ app.post("/newlog", (req, res) => { logger.log(message, type, user, record, object); }); +var os = require("./server/opensearch/os-handler"); +app.post( + "/opensearch", //fb.validateFirebaseIdToken, + os.handler +); +app.post("/search", fb.validateFirebaseIdToken, os.search); + var cdkGetMake = require("./server/cdk/cdk-get-makes"); app.post("/cdk/getvehicles", fb.validateFirebaseIdToken, cdkGetMake.default); diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index 9244dfb5c..e98cdaf9a 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -1757,3 +1757,11 @@ exports.UPDATE_PARTS_CRITICAL = `mutation UPDATE_PARTS_CRITICAL ($IdsToMarkCriti affected_rows } }`; + +exports.ACTIVE_SHOP_BY_USER = `query ACTIVE_SHOP_BY_USER($user: String) { + associations(where: {active: {_eq: true}, useremail: {_eq: $user}}) { + id + shopid + } +} +`; diff --git a/server/opensearch/os-handler.js b/server/opensearch/os-handler.js new file mode 100644 index 000000000..c60902077 --- /dev/null +++ b/server/opensearch/os-handler.js @@ -0,0 +1,251 @@ +const Dinero = require("dinero.js"); +const queries = require("../graphql-client/queries"); +//const client = require("../graphql-client/graphql-client").client; +const _ = require("lodash"); +const GraphQLClient = require("graphql-request").GraphQLClient; +const logger = require("../utils/logger"); + +const path = require("path"); +const client = require("../graphql-client/graphql-client").client; +require("dotenv").config({ + path: path.resolve( + process.cwd(), + `.env.${process.env.NODE_ENV || "development"}` + ), +}); +const { Client, Connection } = require("@opensearch-project/opensearch"); +const { defaultProvider } = require("@aws-sdk/credential-provider-node"); +const aws4 = require("aws4"); +const { gql } = require("graphql-request"); + +var host = process.env.OPEN_SEARCH_HOST; +const createAwsConnector = (credentials, region) => { + class AmazonConnection extends Connection { + buildRequestObject(params) { + const request = super.buildRequestObject(params); + request.service = "es"; + request.region = region; + request.headers = request.headers || {}; + request.headers["host"] = request.hostname; + + return aws4.sign(request, credentials); + } + } + return { + Connection: AmazonConnection, + }; +}; + +const getClient = async () => { + const credentials = await defaultProvider()(); + return new Client({ + ...createAwsConnector(credentials, "ca-central-1"), + node: host, + }); +}; + +async function OpenSearchUpdateHandler(req, res) { + try { + var osClient = await getClient(); + // const osClient = new Client({ + // node: `https://imex:@search-imexonline-search-ixp2stfvwp6qocjsowzjzyreoy.ca-central-1.es.amazonaws.com/`, + // }); + + if (req.body.event.op === "DELETE") { + let response; + response = await osClient.delete({ + id: req.body.event.data.old.id, + index: req.body.table.name, + }); + res.status(200).json(response.body); + } else { + let document; + + switch (req.body.table.name) { + case "jobs": + document = _.pick(req.body.event.data.new, [ + "id", + "bodyshopid", + "ro_number", + "clm_no", + "ownr_fn", + "ownr_ln", + "status", + "ownr_co_nm", + "v_model_yr", + "v_make_desc", + "v_model_desc", + ]); + document.bodyshopid = req.body.event.data.new.shopid; + break; + case "vehicles": + document = _.pick(req.body.event.data.new, [ + "id", + "v_model_yr", + "v_model_desc", + "v_make_desc", + "v_color", + "v_vin", + "plate_no", + ]); + document.bodyshopid = req.body.event.data.new.shopid; + break; + case "owners": + document = _.pick(req.body.event.data.new, [ + "id", + "ownr_fn", + "ownr_ln", + "ownr_co_nm", + "ownr_ph1", + "ownr_ph2", + ]); + document.bodyshopid = req.body.event.data.new.shopid; + break; + case "bills": + const bill = await client.request( + `query ADMIN_GET_BILL_BY_ID($billId: uuid!) { + bills_by_pk(id: $billId) { + id + job { + id + ro_number + shopid + } + vendor { + id + name + } + } + } + `, + { billId: req.body.event.data.new.id } + ); + + document = { + ..._.pick(req.body.event.data.new, [ + "id", + "invoice_number", + "date", + ]), + ...bill.bills_by_pk, + bodyshopid: bill.bills_by_pk.job.shopid, + }; + + break; + case "payments": + //Query to get the job and RO number + const payment = await client.request( + `query ADMIN_GET_PAYMENT_BY_ID($paymentId: uuid!) { + payments_by_pk(id: $paymentId) { + id + job { + id + ro_number + shopid + } + } + } + + `, + { paymentId: req.body.event.data.new.id } + ); + document = { + ..._.pick(req.body.event.data.new, ["id", "invoice_number"]), + ...payment.payments_by_pk, + bodyshopid: bill.payments_by_pk.job.shopid, + }; + break; + } + + const payload = { + id: req.body.event.data.new.id, + index: req.body.table.name, + body: document, + }; + + let response; + response = await osClient.index(payload); + console.log(response.body); + res.status(200).json(response.body); + } + } catch (error) { + res.status(400).json(JSON.stringify(error)); + } finally { + } +} + +async function OpensearchSearchHandler(req, res) { + try { + const { search, bodyshopid } = req.body; + if (!req.user) { + res.sendStatus(401); + return; + } + logger.log("os-search", "DEBUG", req.user.email, null, { + search, + }); + + const BearerToken = req.headers.authorization; + const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, { + headers: { + Authorization: BearerToken, + }, + }); + + const assocs = await client + .setHeaders({ Authorization: BearerToken }) + .request(queries.ACTIVE_SHOP_BY_USER, { + user: req.user.email, + }); + + if (assocs.length === 0) { + res.sendStatus(401); + } + + var osClient = await getClient(); + + const { body } = await osClient.search({ + body: { + size: 100, + query: { + bool: { + must: [ + { + multi_match: { + query: search, + //fields: ["*"], + fuzziness: "AUTO", + prefix_length: 2, + }, + }, + { + match: { + bodyshopid: assocs.associations[0].shopid, + }, + }, + ], + }, + }, + sort: [ + { + _score: { + order: "desc", + }, + }, + ], + }, + }); + + res.json(body); + } catch (error) { + console.log(error); + logger.log("os-search-error", "ERROR", req.user.email, null, { + error: JSON.stringify(error), + }); + res.status(400).json(error); + } finally { + } +} + +exports.handler = OpenSearchUpdateHandler; +exports.search = OpensearchSearchHandler; diff --git a/yarn.lock b/yarn.lock index ec1a3d716..9659256b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4321,6 +4321,11 @@ tslib@^2.3.1, tslib@^2.5.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== +tslib@^2.3.1, tslib@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== + tsscmp@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb"