From f5834ae6bc23017d619de18a5ce6946e10c1083e Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Tue, 14 Jun 2022 09:55:46 -0700 Subject: [PATCH 1/6] Updated dev end points. --- firebase/readme.md | 2 +- hasura/config.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firebase/readme.md b/firebase/readme.md index a1b2e503b..70f865aff 100644 --- a/firebase/readme.md +++ b/firebase/readme.md @@ -1,3 +1,3 @@ Must set the environment variables using: -firebase functions:config:set auth.graphql_endpoint="https://bodyshop-dev-db.herokuapp.com/v1/graphql" auth.hasura_secret_admin_key="Dev-BodyShopApp!" +firebase functions:config:set auth.graphql_endpoint="https://db.dev.bodyshop.app/v1/graphql" auth.hasura_secret_admin_key="Dev-BodyShopApp!" diff --git a/hasura/config.yaml b/hasura/config.yaml index 8b52487b5..fe93f9198 100644 --- a/hasura/config.yaml +++ b/hasura/config.yaml @@ -1,5 +1,5 @@ version: 2 -endpoint: https://bodyshop-dev-db.herokuapp.com +endpoint: https://db.dev.bodyshop.app admin_secret: Dev-BodyShopApp! metadata_directory: metadata actions: From 4fdd48c2798affb82b5a9ced75d44f7cc132c9ee Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Tue, 14 Jun 2022 11:32:29 -0700 Subject: [PATCH 2/6] Update developement db addresses. --- firebase/readme.md | 2 +- hasura/config.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firebase/readme.md b/firebase/readme.md index 70f865aff..c7a2bae6b 100644 --- a/firebase/readme.md +++ b/firebase/readme.md @@ -1,3 +1,3 @@ Must set the environment variables using: -firebase functions:config:set auth.graphql_endpoint="https://db.dev.bodyshop.app/v1/graphql" auth.hasura_secret_admin_key="Dev-BodyShopApp!" +firebase functions:config:set auth.graphql_endpoint="https://db.development.bodyshop.app/v1/graphql" auth.hasura_secret_admin_key="Dev-BodyShopApp!" diff --git a/hasura/config.yaml b/hasura/config.yaml index fe93f9198..ee9b6394b 100644 --- a/hasura/config.yaml +++ b/hasura/config.yaml @@ -1,5 +1,5 @@ version: 2 -endpoint: https://db.dev.bodyshop.app +endpoint: https://db.development.bodyshop.app admin_secret: Dev-BodyShopApp! metadata_directory: metadata actions: From 7ba3cc5ffae252ce0ae5eeac828196d71bea1ee4 Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Wed, 15 Jun 2022 19:03:31 -0700 Subject: [PATCH 3/6] Added basic creation of shops. --- bodyshop_translations.babel | 21 +++ .../documents-upload.utility.js | 2 +- client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 1 + server.js | 14 ++ server/admin/adminops.js | 68 +++++++++ server/firebase/firebase-handler.js | 143 ++++++++++++++---- server/utils/logger.js | 2 +- 9 files changed, 218 insertions(+), 35 deletions(-) create mode 100644 server/admin/adminops.js diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index d6fc28db9..9627b84dd 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -44929,6 +44929,27 @@ signinerror + + auth/user-disabled + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + auth/user-not-found false diff --git a/client/src/components/documents-upload/documents-upload.utility.js b/client/src/components/documents-upload/documents-upload.utility.js index 9e39c8cf9..48a83c7de 100644 --- a/client/src/components/documents-upload/documents-upload.utility.js +++ b/client/src/components/documents-upload/documents-upload.utility.js @@ -54,7 +54,7 @@ export const uploadToCloudinary = async ( //Set variables for getting the signed URL. let timestamp = Math.floor(Date.now() / 1000); let public_id = key; - let tags = `${bodyshop.textid},${ + let tags = `${bodyshop.imexshopid},${ tagsArray ? tagsArray.map((tag) => `${tag},`) : "" }`; // let eager = process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS; diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index c11263fe2..7d7c40ce5 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -2668,6 +2668,7 @@ "users": { "errors": { "signinerror": { + "auth/user-disabled": "User account disabled. ", "auth/user-not-found": "A user with this email does not exist.", "auth/wrong-password": "The email and password combination you provided is incorrect." } diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 25d8103dd..430f2aac9 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -2668,6 +2668,7 @@ "users": { "errors": { "signinerror": { + "auth/user-disabled": "", "auth/user-not-found": "", "auth/wrong-password": "" } diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index b0b95f0ba..8d3038bde 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -2668,6 +2668,7 @@ "users": { "errors": { "signinerror": { + "auth/user-disabled": "", "auth/user-not-found": "", "auth/wrong-password": "" } diff --git a/server.js b/server.js index 60f772e49..8b21072d8 100644 --- a/server.js +++ b/server.js @@ -157,7 +157,21 @@ app.post( fb.unsubscribe ); app.post("/adm/updateuser", fb.validateFirebaseIdToken, fb.updateUser); +app.post("/adm/getuser", fb.validateFirebaseIdToken, fb.getUser); app.post("/adm/createuser", fb.validateFirebaseIdToken, fb.createUser); +const adm = require("./server/admin/adminops"); +app.post( + "/adm/createassociation", + fb.validateFirebaseIdToken, + fb.validateAdmin, + adm.createAssociation +); +app.post( + "/adm/createshop", + fb.validateFirebaseIdToken, + fb.validateAdmin, + adm.createShop +); //Stripe Processing var stripe = require("./server/stripe/payment"); diff --git a/server/admin/adminops.js b/server/admin/adminops.js new file mode 100644 index 000000000..eed2bcb79 --- /dev/null +++ b/server/admin/adminops.js @@ -0,0 +1,68 @@ +const path = require("path"); + +const _ = require("lodash"); +const logger = require("../utils/logger"); +require("dotenv").config({ + path: path.resolve( + process.cwd(), + `.env.${process.env.NODE_ENV || "development"}` + ), +}); + +const client = require("../graphql-client/graphql-client").client; + +exports.createAssociation = async (req, res) => { + logger.log("admin-create-association", "ADMIN", req.user.email, null, { + request: req.body, + ioadmin: true, + }); + const { shopid, authlevel, useremail } = req.body; + + const result = await client.request( + `mutation INSERT_ASSOCIATION($assoc: associations_insert_input!){ + insert_associations_one(object:$assoc){ + id + authlevel + useremail + active + } +}`, + { + assoc: { shopid, authlevel, useremail, active: false }, + } + ); + res.json(result); +}; +exports.createShop = async (req, res) => { + logger.log("admin-create-shop", "ADMIN", req.user.email, null, { + request: req.body, + ioadmin: true, + }); + const { bodyshop, ronum } = req.body; + + try { + const result = await client.request( + `mutation INSERT_BODYSHOPS($bs: bodyshops_insert_input!){ + insert_bodyshops_one(object:$bs){ + id + + } +}`, + { + bs: { + ...bodyshop, + counters: { + data: [ + { countertype: "ronum", count: ronum }, + { countertype: "ihbnum", count: 1 }, + { countertype: "paymentnum", count: 1 }, + ], + }, + }, + } + ); + res.json(result); + } catch (error) { + res.status(500).json(error); + } +}; diff --git a/server/firebase/firebase-handler.js b/server/firebase/firebase-handler.js index 05a5e38aa..8fae9d96a 100644 --- a/server/firebase/firebase-handler.js +++ b/server/firebase/firebase-handler.js @@ -1,13 +1,14 @@ var admin = require("firebase-admin"); const logger = require("../utils/logger"); const path = require("path"); +const { auth } = require("firebase-admin"); require("dotenv").config({ path: path.resolve( process.cwd(), `.env.${process.env.NODE_ENV || "development"}` ), }); - +const client = require("../graphql-client/graphql-client").client; var serviceAccount = require(process.env.FIREBASE_ADMINSDK_JSON); admin.initializeApp({ @@ -19,54 +20,61 @@ exports.admin = admin; const adminEmail = [ "patrick@imex.dev", - "patrick@imex.text", + //"patrick@imex.test", "patrick@imex.prod", "patrick@imexsystems.ca", "patrick@thinkimex.com", ]; -exports.createUser = (req, res) => { - logger.log("admin-create-user", "WARN", req.user.email, null, { +exports.createUser = async (req, res) => { + logger.log("admin-create-user", "ADMIN", req.user.email, null, { request: req.body, + ioadmin: true, }); - if (!adminEmail.includes(req.user.email)) { - logger.log( - "admin-create-user-unauthorized", - "ERROR", - req.user.email, - null, + + const { email, displayName, password, shopid, authlevel } = req.body; + try { + const userRecord = await admin + .auth() + .createUser({ email, displayName, password }); + + // See the UserRecord reference doc for the contents of userRecord. + + const result = await client.request( + ` + mutation INSERT_USER($user: users_insert_input!) { + insert_users_one(object: $user) { + email + } + } + `, { - request: req.body, - user: req.user, + user: { + email, + authid: userRecord.uid, + associations: { + data: [{ shopid, authlevel, active: true }], + }, + }, } ); - res.sendStatus(404); - } - const { email, displayName, password } = req.body; - admin - .auth() - .createUser({ email, displayName, password }) - .then((userRecord) => { - // See the UserRecord reference doc for the contents of userRecord. - logger.log("admin-update-user-success", "DEBUG", req.user.email, null, { - userRecord, - }); - res.json(userRecord); - }) - .catch((error) => { - logger.log("admin-update-user-error", "ERROR", req.user.email, null, { - error, - }); - res.status(500).json(error); + res.json({ userRecord, result }); + } catch (error) { + logger.log("admin-update-user-error", "ERROR", req.user.email, null, { + error, }); + res.status(500).json(error); + } }; exports.updateUser = (req, res) => { - logger.log("admin-update-user", "WARN", req.user.email, null, { + logger.log("admin-update-user", "ADMIN", req.user.email, null, { request: req.body, + ioadmin: true, }); - if (!adminEmail.includes(req.user.email)) { + + if (!adminEmail.includes(req.user.email) && !req.user.ioadmin) { logger.log( "admin-update-user-unauthorized", "ERROR", @@ -78,6 +86,7 @@ exports.updateUser = (req, res) => { } ); res.sendStatus(404); + return; } admin @@ -98,8 +107,9 @@ exports.updateUser = (req, res) => { .then((userRecord) => { // See the UserRecord reference doc for the contents of userRecord. - logger.log("admin-update-user-success", "DEBUG", req.user.email, null, { + logger.log("admin-update-user-success", "ADMIN", req.user.email, null, { userRecord, + ioadmin: true, }); res.json(userRecord); }) @@ -111,6 +121,41 @@ exports.updateUser = (req, res) => { }); }; +exports.getUser = (req, res) => { + logger.log("admin-get-user", "ADMIN", req.user.email, null, { + request: req.body, + ioadmin: true, + }); + + if (!adminEmail.includes(req.user.email) && !req.user.ioadmin) { + logger.log( + "admin-update-user-unauthorized", + "ERROR", + req.user.email, + null, + { + request: req.body, + user: req.user, + } + ); + res.sendStatus(404); + return; + } + + admin + .auth() + .getUser(req.body.uid) + .then((userRecord) => { + res.json(userRecord); + }) + .catch((error) => { + logger.log("admin-get-user-error", "ERROR", req.user.email, null, { + error, + }); + res.status(500).json(error); + }); +}; + exports.sendNotification = async (req, res) => { setTimeout(() => { // Send a message to the device corresponding to the provided @@ -221,3 +266,35 @@ exports.validateFirebaseIdToken = async (req, res, next) => { return; } }; + +exports.validateAdmin = async (req, res, next) => { + if (!adminEmail.includes(req.user.email) && !req.user.ioadmin) { + logger.log("admin-validation-failed", "ERROR", req.user.email, null, { + request: req.body, + user: req.user, + }); + res.sendStatus(404); + return; + } else { + next(); + return; + } +}; + +//Admin claims code. +// const uid = "JEqqYlsadwPEXIiyRBR55fflfko1"; + +// admin +// .auth() +// .getUser(uid) +// .then((user) => { +// console.log(user); +// admin.auth().setCustomUserClaims(uid, { +// ioadmin: true, +// "https://hasura.io/jwt/claims": { +// "x-hasura-default-role": "admin", +// "x-hasura-allowed-roles": ["admin"], +// "x-hasura-user-id": uid, +// }, +// }); +// }); diff --git a/server/utils/logger.js b/server/utils/logger.js index 1a676b4b4..0dae8af18 100644 --- a/server/utils/logger.js +++ b/server/utils/logger.js @@ -13,7 +13,7 @@ function log(message, type, user, record, object) { record, ...object, }); - logger.log(message, { + logger.log(message, message, { type, env: process.env.NODE_ENV || "development", user, From 1e88d5ae1b2dcafa6cb89085b3e0f0372c49a2b5 Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Fri, 17 Jun 2022 15:22:29 -0700 Subject: [PATCH 4/6] IO-1937 Add 10mb limit for emails. --- bodyshop_translations.babel | 21 + .../email-documents.component.jsx | 12 + .../email-overlay/email-overlay.component.jsx | 17 + .../error-boundary.component.jsx | 1 + ...s-documents-gallery.external.component.jsx | 1 + .../pages/manage/manage.page.component.jsx | 7 +- client/src/translations/en_us/common.json | 3 +- client/src/translations/es/common.json | 3 +- client/src/translations/fr/common.json | 3 +- client/src/utils/RenderTemplate.js | 2 +- package-lock.json | 12049 ++++++++++++++++ server/email/sendemail.js | 6 +- yarn.lock | 6670 ++++----- 13 files changed, 15461 insertions(+), 3334 deletions(-) create mode 100644 package-lock.json diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 9627b84dd..93d42f810 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -15374,6 +15374,27 @@ + + sizelimit + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + diff --git a/client/src/components/email-documents/email-documents.component.jsx b/client/src/components/email-documents/email-documents.component.jsx index abbcfea0d..7b3f393ae 100644 --- a/client/src/components/email-documents/email-documents.component.jsx +++ b/client/src/components/email-documents/email-documents.component.jsx @@ -38,6 +38,12 @@ export function EmailDocumentsComponent({ nextFetchPolicy: "network-only", }); + console.log( + selectedMedia && + selectedMedia + .filter((s) => s.isSelected) + .reduce((acc, val) => (acc = acc + val.size), 0) + ); return ( {loading && } @@ -45,6 +51,12 @@ export function EmailDocumentsComponent({ {selectedMedia.filter((s) => s.isSelected).length >= 10 ? ( {t("messaging.labels.maxtenimages")} ) : null} + {selectedMedia && + selectedMedia + .filter((s) => s.isSelected) + .reduce((acc, val) => (acc = acc + val.size), 0) >= 9961472 ? ( + {t("general.errors.sizelimit")} + ) : null} {data && ( ({ + validator(rule, value) { + const totalSize = value.reduce( + (acc, val) => (acc = acc + val.size), + 0 + ); + + const limit = 9961472; + + if (totalSize > limit) { + return Promise.reject(t("general.errors.sizelimit")); + } + return Promise.resolve(); + }, + }), + ]} > getDerivedStateFromError -> error", error); + return { hasErrored: true, error: error }; } diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.external.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.external.component.jsx index 278fe59d9..fe23d8ceb 100644 --- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.external.component.jsx +++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.external.component.jsx @@ -25,6 +25,7 @@ function JobsDocumentGalleryExternal({ id: value.id, type: value.type, tags: [{ value: value.type, title: value.type }], + size: value.size, }); } diff --git a/client/src/pages/manage/manage.page.component.jsx b/client/src/pages/manage/manage.page.component.jsx index 82017ffae..97f8cb71c 100644 --- a/client/src/pages/manage/manage.page.component.jsx +++ b/client/src/pages/manage/manage.page.component.jsx @@ -24,6 +24,8 @@ import { selectBodyshop, selectInstanceConflict, } from "../../redux/user/user.selectors"; +import * as Sentry from "@sentry/react"; + import "./manage.page.styles.scss"; const ManageRootPage = lazy(() => @@ -407,7 +409,10 @@ export function Manage({ match, conflict, bodyshop }) { - {PageContent} + } showDialog> + {PageContent} + +