From fa29bd609f223dbd76bce6d41bf85bfc2d91d546 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Thu, 27 Feb 2025 12:15:36 -0800 Subject: [PATCH] IO-3092 Additional comments, email compatibility. --- .../chat-media-selector.component.jsx | 55 ++++++++++++------- .../documents-upload-imgproxy.utility.js | 2 +- .../email-documents.component.jsx | 51 +++++++++++++---- ...bs-document-gallery.download.component.jsx | 8 ++- ...bs-document-gallery.reassign.component.jsx | 8 ++- .../jobs-documents-gallery.component.jsx | 8 ++- .../jobs-documents-gallery.container.jsx | 8 ++- ...obs-documents-gallery.delete.component.jsx | 9 ++- ...s-documents-gallery.external.component.jsx | 7 +++ ...-documents-gallery.selectall.component.jsx | 8 +++ ...nt-imgproxy-gallery.download.component.jsx | 9 +++ ...nt-imgproxy-gallery.reassign.component.jsx | 8 ++- ...s-documents-imgproxy-gallery.component.jsx | 8 ++- ...s-documents-imgproxy-gallery.container.jsx | 8 +++ ...ents-imgproxy-gallery.delete.component.jsx | 10 +++- ...ts-imgproxy-gallery.external.component.jsx | 9 ++- ...s-imgproxy-gallery.selectall.component.jsx | 8 +++ .../{imgprox-media.js => imgproxy-media.js} | 15 +---- server/routes/mediaRoutes.js | 2 +- 19 files changed, 185 insertions(+), 56 deletions(-) rename server/media/{imgprox-media.js => imgproxy-media.js} (95%) diff --git a/client/src/components/chat-media-selector/chat-media-selector.component.jsx b/client/src/components/chat-media-selector/chat-media-selector.component.jsx index cc7a56b73..b7e7d64a3 100644 --- a/client/src/components/chat-media-selector/chat-media-selector.component.jsx +++ b/client/src/components/chat-media-selector/chat-media-selector.component.jsx @@ -51,9 +51,10 @@ export function ChatMediaSelector({ bodyshop, selectedMedia, setSelectedMedia, c setSelectedMedia([]); }, [setSelectedMedia, conversation]); - - //Knowingly taking on the technical debt of poor implementation below. - //Cloudinary will be removed once the migration is completed. + //Knowingly taking on the technical debt of poor implementation below. Done this way to avoid an edge case where no component may be displayed. + //Cloudinary will be removed once the migration is completed. + //If Imageproxy is on, rely only on the LMS selector + //If not on, use the old methods. const content = (
{loading && } @@ -61,23 +62,37 @@ export function ChatMediaSelector({ bodyshop, selectedMedia, setSelectedMedia, c {selectedMedia.filter((s) => s.isSelected).length >= 10 ? (
{t("messaging.labels.maxtenimages")}
) : null} - {Imgproxy.treatment === "on" && !bodyshop.uselocalmediaserver && data && ( - - )} - {Imgproxy.treatment !== "on" && !bodyshop.uselocalmediaserver && data && ( - - )} - {Imgproxy.treatment !== "on" && bodyshop.uselocalmediaserver && open && ( - + + {Imgproxy.treatment === "on" ? ( + <> + {!bodyshop.uselocalmediaserver && ( + + )} + {bodyshop.uselocalmediaserver && open && ( + + )} + + ) : ( + <> + {!bodyshop.uselocalmediaserver && data && ( + + )} + {bodyshop.uselocalmediaserver && open && ( + + )} + )}
); diff --git a/client/src/components/documents-upload-imgproxy/documents-upload-imgproxy.utility.js b/client/src/components/documents-upload-imgproxy/documents-upload-imgproxy.utility.js index 184cf86c6..ed64f5efb 100644 --- a/client/src/components/documents-upload-imgproxy/documents-upload-imgproxy.utility.js +++ b/client/src/components/documents-upload-imgproxy/documents-upload-imgproxy.utility.js @@ -74,7 +74,7 @@ export const uploadToS3 = async ( const exif = await exifr.parse(file); takenat = exif && exif.DateTimeOriginal; } catch (error) { - console.log("Unable to parse image file for EXIF Data"); + console.log("Unable to parse image file for EXIF Data", error.message); } } diff --git a/client/src/components/email-documents/email-documents.component.jsx b/client/src/components/email-documents/email-documents.component.jsx index d3c6b20da..7e17d5565 100644 --- a/client/src/components/email-documents/email-documents.component.jsx +++ b/client/src/components/email-documents/email-documents.component.jsx @@ -10,6 +10,8 @@ import AlertComponent from "../alert/alert.component"; import JobDocumentsGalleryExternal from "../jobs-documents-gallery/jobs-documents-gallery.external.component"; import JobsDocumentsLocalGalleryExternalComponent from "../jobs-documents-local-gallery/jobs-documents-local-gallery.external.component"; import LoadingSpinner from "../loading-spinner/loading-spinner.component"; +import { useSplitTreatments } from "@splitsoftware/splitio-react"; +import JobsDocumentImgproxyGalleryExternal from "../jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.external.component"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser @@ -23,6 +25,13 @@ export default connect(mapStateToProps, mapDispatchToProps)(EmailDocumentsCompon export function EmailDocumentsComponent({ emailConfig, form, selectedMediaState, bodyshop }) { const { t } = useTranslation(); + const { + treatments: { Imgproxy } + } = useSplitTreatments({ + attributes: {}, + names: ["Imgproxy"], + splitKey: bodyshop && bodyshop.imexshopid + }); const [selectedMedia, setSelectedMedia] = selectedMediaState; const { loading, error, data } = useQuery(GET_DOCUMENTS_BY_JOB, { @@ -46,17 +55,37 @@ export function EmailDocumentsComponent({ emailConfig, form, selectedMediaState, 10485760 - new Blob([form.getFieldValue("html")]).size ? (
{t("general.errors.sizelimit")}
) : null} - {!bodyshop.uselocalmediaserver && data && ( - - )} - {bodyshop.uselocalmediaserver && ( - + + {Imgproxy.treatment === "on" ? ( + <> + {!bodyshop.uselocalmediaserver && data && ( + + )} + {bodyshop.uselocalmediaserver && ( + + )} + + ) : ( + <> + {!bodyshop.uselocalmediaserver && data && ( + + )} + {bodyshop.uselocalmediaserver && ( + + )} + )} ); diff --git a/client/src/components/jobs-documents-gallery/jobs-document-gallery.download.component.jsx b/client/src/components/jobs-documents-gallery/jobs-document-gallery.download.component.jsx index f85db7c8c..cbc89ab38 100644 --- a/client/src/components/jobs-documents-gallery/jobs-document-gallery.download.component.jsx +++ b/client/src/components/jobs-documents-gallery/jobs-document-gallery.download.component.jsx @@ -19,7 +19,13 @@ const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) }); export default connect(mapStateToProps, mapDispatchToProps)(JobsDocumentsDownloadButton); - +/* +################################################################################################ + Developer Note: + Known Technical Debt Item + Modifications to this code requires complementary changes to the Imgproxy code. This code will be removed once the imgproxy migration is completed. +################################################################################################ +*/ export function JobsDocumentsDownloadButton({ bodyshop, galleryImages, identifier }) { const { t } = useTranslation(); const [download, setDownload] = useState(null); diff --git a/client/src/components/jobs-documents-gallery/jobs-document-gallery.reassign.component.jsx b/client/src/components/jobs-documents-gallery/jobs-document-gallery.reassign.component.jsx index 33f2e964a..51c889729 100644 --- a/client/src/components/jobs-documents-gallery/jobs-document-gallery.reassign.component.jsx +++ b/client/src/components/jobs-documents-gallery/jobs-document-gallery.reassign.component.jsx @@ -17,7 +17,13 @@ const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) }); export default connect(mapStateToProps, mapDispatchToProps)(JobsDocumentsGalleryReassign); - +/* +################################################################################################ + Developer Note: + Known Technical Debt Item + Modifications to this code requires complementary changes to the Imgproxy code. This code will be removed once the imgproxy migration is completed. +################################################################################################ +*/ export function JobsDocumentsGalleryReassign({ bodyshop, galleryImages, callback }) { const { t } = useTranslation(); const [form] = Form.useForm(); diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx index fdc919320..58adaccad 100644 --- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx +++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx @@ -22,7 +22,13 @@ const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop }); const mapDispatchToProps = (dispatch) => ({}); - +/* +################################################################################################ + Developer Note: + Known Technical Debt Item + Modifications to this code requires complementary changes to the Imgproxy code. This code will be removed once the imgproxy migration is completed. +################################################################################################ +*/ function JobsDocumentsComponent({ bodyshop, data, diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.container.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.container.jsx index 3c2cf3843..5bbd95f94 100644 --- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.container.jsx +++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.container.jsx @@ -14,7 +14,13 @@ const mapStateToProps = createStructuredSelector({ }); const mapDispatchToProps = (dispatch) => ({}); export default connect(mapStateToProps, mapDispatchToProps)(JobsDocumentsContainer); - +/* +################################################################################################ + Developer Note: + Known Technical Debt Item + Modifications to this code requires complementary changes to the Imgproxy code. This code will be removed once the imgproxy migration is completed. +################################################################################################ +*/ export function JobsDocumentsContainer({ jobId, billId, diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.delete.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.delete.component.jsx index 5cd1fcb06..4b92e4c99 100644 --- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.delete.component.jsx +++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.delete.component.jsx @@ -5,8 +5,13 @@ import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { logImEXEvent } from "../../firebase/firebase.utils"; import { useNotification } from "../../contexts/Notifications/notificationContext.jsx"; -//Context: currentUserEmail, bodyshop, jobid, invoiceid - +/* +################################################################################################ + Developer Note: + Known Technical Debt Item + Modifications to this code requires complementary changes to the Imgproxy code. This code will be removed once the imgproxy migration is completed. +################################################################################################ +*/ export default function JobsDocumentsDeleteButton({ galleryImages, deletionCallback }) { const { t } = useTranslation(); const notification = useNotification(); 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 940598052..d4340bb98 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 @@ -3,6 +3,13 @@ import { Gallery } from "react-grid-gallery"; import { useTranslation } from "react-i18next"; import { GenerateSrcUrl, GenerateThumbUrl } from "./job-documents.utility"; +/* +################################################################################################ + Developer Note: + Known Technical Debt Item + Modifications to this code requires complementary changes to the Imgproxy code. This code will be removed once the imgproxy migration is completed. +################################################################################################ +*/ function JobsDocumentGalleryExternal({ data, diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.selectall.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.selectall.component.jsx index 122ce6236..157e04dca 100644 --- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.selectall.component.jsx +++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.selectall.component.jsx @@ -2,6 +2,14 @@ import { Button, Space } from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; +/* +################################################################################################ + Developer Note: + Known Technical Debt Item + Modifications to this code requires complementary changes to the Imgproxy code. This code will be removed once the imgproxy migration is completed. +################################################################################################ +*/ + export default function JobsDocumentsGallerySelectAllComponent({ galleryImages, setGalleryImages }) { const { t } = useTranslation(); diff --git a/client/src/components/jobs-documents-imgproxy-gallery/jobs-document-imgproxy-gallery.download.component.jsx b/client/src/components/jobs-documents-imgproxy-gallery/jobs-document-imgproxy-gallery.download.component.jsx index 2d649bcc9..6c08936dc 100644 --- a/client/src/components/jobs-documents-imgproxy-gallery/jobs-document-imgproxy-gallery.download.component.jsx +++ b/client/src/components/jobs-documents-imgproxy-gallery/jobs-document-imgproxy-gallery.download.component.jsx @@ -17,6 +17,15 @@ const mapStateToProps = createStructuredSelector({ const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) }); + +/* +################################################################################################ + Developer Note: + Known Technical Debt Item + Modifications to this code requires complementary changes to the Cloudinary code. Cloudinary code will be removed upon completed migration. +################################################################################################ +*/ + export default connect(mapStateToProps, mapDispatchToProps)(JobsDocumentsImgproxyDownloadButton); export function JobsDocumentsImgproxyDownloadButton({ bodyshop, galleryImages, identifier }) { diff --git a/client/src/components/jobs-documents-imgproxy-gallery/jobs-document-imgproxy-gallery.reassign.component.jsx b/client/src/components/jobs-documents-imgproxy-gallery/jobs-document-imgproxy-gallery.reassign.component.jsx index 19b7d9352..4ce2d12a2 100644 --- a/client/src/components/jobs-documents-imgproxy-gallery/jobs-document-imgproxy-gallery.reassign.component.jsx +++ b/client/src/components/jobs-documents-imgproxy-gallery/jobs-document-imgproxy-gallery.reassign.component.jsx @@ -17,7 +17,13 @@ const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) }); export default connect(mapStateToProps, mapDispatchToProps)(JobsDocumentsImgproxyGalleryReassign); - +/* +################################################################################################ + Developer Note: + Known Technical Debt Item + Modifications to this code requires complementary changes to the Cloudinary code. Cloudinary code will be removed upon completed migration. +################################################################################################ +*/ export function JobsDocumentsImgproxyGalleryReassign({ bodyshop, galleryImages, callback }) { const { t } = useTranslation(); const [form] = Form.useForm(); diff --git a/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.component.jsx b/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.component.jsx index b28d3f1bd..156362ff1 100644 --- a/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.component.jsx +++ b/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.component.jsx @@ -22,7 +22,13 @@ const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop }); const mapDispatchToProps = (dispatch) => ({}); - +/* +################################################################################################ + Developer Note: + Known Technical Debt Item + Modifications to this code requires complementary changes to the Cloudinary code. Cloudinary code will be removed upon completed migration. +################################################################################################ +*/ function JobsDocumentsImgproxyComponent({ bodyshop, data, diff --git a/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.container.jsx b/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.container.jsx index 50dd4bbe9..9191b262c 100644 --- a/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.container.jsx +++ b/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.container.jsx @@ -4,6 +4,14 @@ import AlertComponent from "../alert/alert.component"; import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import JobDocuments from "./jobs-documents-imgproxy-gallery.component"; +/* +################################################################################################ + Developer Note: + Known Technical Debt Item + Modifications to this code requires complementary changes to the Cloudinary code. Cloudinary code will be removed upon completed migration. +################################################################################################ +*/ + export default function JobsDocumentsImgproxyContainer({ jobId, billId, documentsList, billsCallback }) { const { loading, error, data, refetch } = useQuery(GET_DOCUMENTS_BY_JOB, { variables: { jobId: jobId }, diff --git a/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.delete.component.jsx b/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.delete.component.jsx index 51ebfbf2b..72143531b 100644 --- a/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.delete.component.jsx +++ b/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.delete.component.jsx @@ -5,7 +5,15 @@ import { useState } from "react"; import { useTranslation } from "react-i18next"; import { logImEXEvent } from "../../firebase/firebase.utils.js"; import { useNotification } from "../../contexts/Notifications/notificationContext.jsx"; -//Context: currentUserEmail, bodyshop, jobid, invoiceid + + +/* +################################################################################################ + Developer Note: + Known Technical Debt Item + Modifications to this code requires complementary changes to the Cloudinary code. Cloudinary code will be removed upon completed migration. +################################################################################################ +*/ export default function JobsDocumentsImgproxyDeleteButton({ galleryImages, deletionCallback }) { const { t } = useTranslation(); diff --git a/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.external.component.jsx b/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.external.component.jsx index 21c8059f9..75943dceb 100644 --- a/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.external.component.jsx +++ b/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.external.component.jsx @@ -2,7 +2,14 @@ import { useEffect } from "react"; import { Gallery } from "react-grid-gallery"; import { useTranslation } from "react-i18next"; import { fetchImgproxyThumbnails } from "./jobs-documents-imgproxy-gallery.component"; -//import { GenerateSrcUrl, GenerateThumbUrl } from "./job-documents-imgproxy.utility"; + +/* +################################################################################################ + Developer Note: + Known Technical Debt Item + Modifications to this code requires complementary changes to the Cloudinary code. Cloudinary code will be removed upon completed migration. +################################################################################################ +*/ function JobsDocumentImgproxyGalleryExternal({ jobId, externalMediaState }) { const [galleryImages, setgalleryImages] = externalMediaState; diff --git a/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.selectall.component.jsx b/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.selectall.component.jsx index 25162e7d0..4d4b0b32e 100644 --- a/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.selectall.component.jsx +++ b/client/src/components/jobs-documents-imgproxy-gallery/jobs-documents-imgproxy-gallery.selectall.component.jsx @@ -1,6 +1,14 @@ import { Button, Space } from "antd"; import { useTranslation } from "react-i18next"; +/* +################################################################################################ + Developer Note: + Known Technical Debt Item + Modifications to this code requires complementary changes to the Cloudinary code. Cloudinary code will be removed upon completed migration. +################################################################################################ +*/ + export default function JobsDocumentsImgproxyGallerySelectAllComponent({ galleryImages, setGalleryImages }) { const { t } = useTranslation(); diff --git a/server/media/imgprox-media.js b/server/media/imgproxy-media.js similarity index 95% rename from server/media/imgprox-media.js rename to server/media/imgproxy-media.js index 4cb0b7d94..fdb313984 100644 --- a/server/media/imgprox-media.js +++ b/server/media/imgproxy-media.js @@ -24,9 +24,7 @@ const { const archiver = require("archiver"); const stream = require("node:stream"); -const imgproxyBaseUrl = - // `https://u4gzpp5wm437dnm75qa42tvza40fguqr.lambda-url.ca-central-1.on.aws` || //Direct Lambda function access to bypass CDN. - process.env.IMGPROXY_BASE_URL; +const imgproxyBaseUrl = process.env.IMGPROXY_BASE_URL; // `https://u4gzpp5wm437dnm75qa42tvza40fguqr.lambda-url.ca-central-1.on.aws` //Direct Lambda function access to bypass CDN. const imgproxyKey = process.env.IMGPROXY_KEY; const imgproxySalt = process.env.IMGPROXY_SALT; const imgproxyDestinationBucket = process.env.IMGPROXY_DESTINATION_BUCKET; @@ -38,17 +36,9 @@ exports.generateSignedUploadUrls = async (req, res) => { try { logger.log("imgproxy-upload-start", "DEBUG", req.user?.email, jobid, { filenames, bodyshopid, jobid }); - //TODO: Ensure that the user has access to the given bodyshopid. - //This can be done by querying associations, or, maintaining a REDIS cache of user permissions. - const hasAccess = true; //TODO: Ensure this is not hardcoded. - if (!hasAccess) { - res.send(403); - return; - } - const signedUrls = []; for (const filename of filenames) { - const key = filename; //GenerateKey({ bodyshopid, jobid, filename }); + const key = filename; const client = new S3Client({ region: InstanceRegion() }); const command = new PutObjectCommand({ Bucket: imgproxyDestinationBucket, @@ -258,7 +248,6 @@ exports.deleteFiles = async (req, res) => { }); const result = await Promise.all(deleteTransactions); - console.log("*** ~ file: imgprox-media.js:260 ~ exports.deleteFiles ~ result:", result); const errors = result.filter((d) => d.error); //Delete only the succesful deletes. diff --git a/server/routes/mediaRoutes.js b/server/routes/mediaRoutes.js index 293ac51a0..0fcfdd3c5 100644 --- a/server/routes/mediaRoutes.js +++ b/server/routes/mediaRoutes.js @@ -7,7 +7,7 @@ const { downloadFiles: downloadFilesImgproxy, moveFiles, deleteFiles: deleteFilesImgproxy -} = require("../media/imgprox-media"); +} = require("../media/imgproxy-media"); const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware"); const withUserGraphQLClientMiddleware = require("../middleware/withUserGraphQLClientMiddleware");