Add EMS upload for archiving.

This commit is contained in:
Patrick Fic
2025-05-15 14:29:30 -07:00
parent 3f2501cd90
commit cd5ddc4fa1
8 changed files with 740 additions and 200 deletions

View File

@@ -6,4 +6,4 @@ VITE_COMPANY=IMEX
VITE_FE_URL=https://imex.online
VITE_FE_URL_TEST=https://test.imex.online
VITE_API_URL="http://localhost:4000"
VITE_API_TEST_URL="http://api.test.imex.online"
VITE_API_TEST_URL="https://api.test.imex.online"

3
.vscode/launch.json vendored
View File

@@ -13,7 +13,8 @@
"runtimeArgs": ["--sourcemap"],
"env": {
"REMOTE_DEBUGGING_PORT": "9222"
}
},
"experimentalNetworking": "off"
},
{
"name": "Debug Renderer Process",

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.convenientbrands.bodyshop-desktop.keepalive</string>
<key>ProgramArguments</key>
<array>
<string>Shop Partner Keep Alive</string>
<string>imexmedia://keep-alive</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>${KEEP_ALIVE_INTERVAL_SECONDS}</integer>
</dict>
</plist>

788
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "bodyshop-desktop",
"version": "0.0.1-alpha.10",
"version": "0.0.1-alpha.11",
"description": "Shop Management System Partner",
"main": "./out/main/index.js",
"author": "Convenient Brands, LLC",
@@ -55,6 +55,7 @@
"@types/xml2js": "^0.4.14",
"@vitejs/plugin-react": "^4.3.4",
"antd": "^5.24.6",
"archiver": "^7.0.1",
"chokidar": "^4.0.3",
"cors": "^2.8.5",
"dbffile": "^1.12.0",
@@ -72,6 +73,7 @@
"graphql-request": "^7.1.2",
"i18next": "^24.2.3",
"lodash": "^4.17.21",
"node-cron": "^3.0.3",
"playwright": "^1.51.1",
"prettier": "^3.5.3",
"react": "^19.1.0",
@@ -84,7 +86,6 @@
"typescript": "^5.8.3",
"vite": "6.2.6",
"xml2js": "^0.6.2",
"xmlbuilder2": "^3.1.1",
"node-cron": "^3.0.3"
"xmlbuilder2": "^3.1.1"
}
}

View File

@@ -43,6 +43,7 @@ import { DecodedTtl } from "./decode-ttl.interface";
import DecodeVeh from "./decode-veh";
import { DecodedVeh } from "./decode-veh.interface";
import setAppProgressbar from "../util/setAppProgressBar";
import UploadEmsToS3 from "./emsbackup";
async function ImportJob(filepath: string): Promise<void> {
const parsedFilePath = path.parse(filepath);
@@ -191,6 +192,14 @@ async function ImportJob(filepath: string): Promise<void> {
uploadNotification.show();
log.debug("Job inserted", insertRecordResult);
UploadEmsToS3({
extensionlessFilePath,
bodyshopid: newAvailableJob.bodyshopid,
ciecaid: jobObject.ciecaid ?? "",
clm_no: jobObject.clm_no ?? "",
ownr_ln: jobObject.ownr_ln ?? "",
});
} catch (error) {
log.error("Error encountered while decoding job. ", errorTypeCheck(error));
const uploadNotificationFailure = new Notification({

View File

@@ -0,0 +1,104 @@
import axios from "axios";
import archiver from "archiver";
import errorTypeCheck from "../../util/errorTypeCheck";
import { UUID } from "crypto";
import fs from "fs";
import path from "path";
import stream from "stream";
import { getTokenFromRenderer } from "../graphql/graphql-client";
import store from "../store/store";
async function UploadEmsToS3({
extensionlessFilePath,
bodyshopid,
clm_no,
ciecaid,
ownr_ln,
}: {
extensionlessFilePath: string;
bodyshopid: UUID;
clm_no: string;
ciecaid: string;
ownr_ln: string;
}): Promise<boolean> {
// This function is a placeholder for the actual upload logic
try {
const directory = path.dirname(extensionlessFilePath);
const baseFilename = path.basename(extensionlessFilePath);
// Find all files in the directory that start with the base filename
const filesToZip = fs
.readdirSync(directory)
.filter((file) => file.startsWith(baseFilename))
.map((file) => path.join(directory, file));
if (filesToZip.length === 0) {
console.error("No files found to zip.");
return false;
}
// Create a zip archive in memory
const archive = archiver("zip", { zlib: { level: 9 } });
const zipBuffer = await new Promise<Buffer>((resolve, reject) => {
const buffers: Buffer[] = [];
const writableStream = new stream.Writable({
write(chunk, _encoding, callback) {
buffers.push(chunk);
callback();
},
});
writableStream.on("finish", () => resolve(Buffer.concat(buffers)));
writableStream.on("error", reject);
archive.pipe(writableStream);
// Append files to the archive
filesToZip.forEach((file) => {
archive.file(file, { name: path.basename(file) });
});
archive.finalize();
});
// Get the presigned URL from the server
const presignedUrlResponse = await axios.post(
`${
store.get("app.isTest")
? import.meta.env.VITE_API_TEST_URL
: import.meta.env.VITE_API_URL
}/emsupload`,
{
bodyshopid,
ciecaid,
clm_no,
ownr_ln,
},
{
headers: {
Authorization: `Bearer ${await getTokenFromRenderer()}`,
},
},
);
const presignedUrl = presignedUrlResponse.data?.presignedUrl;
if (!presignedUrl) {
console.error("Failed to retrieve presigned URL.");
return false;
}
// Upload the zip file to S3 using the presigned URL
await axios.put(presignedUrl, zipBuffer, {
headers: {
"Content-Type": "application/zip",
},
});
} catch (error) {
console.error("Error uploading EMS to S3:", errorTypeCheck(error));
return false;
}
return true; // Return true if the upload is successful
}
export default UploadEmsToS3;

View File

@@ -26,11 +26,11 @@ const ipcMainHandleAuthStateChanged = async (
log.debug("Received authentication state change from Renderer.", user);
handleShopMetaDataFetch();
//Check for updates
const convCo = Store.get("app.bodyshop");
if (convCo === "alpha") {
const bodyshop = Store.get("app.bodyshop");
if (bodyshop?.convenient_company === "alpha") {
autoUpdater.channel = "alpha";
log.debug("Setting update channel to ALPHA channel.");
} else if (convCo === "beta") {
} else if (bodyshop?.convenient_company === "beta") {
autoUpdater.channel = "beta";
log.debug("Setting update channel to BETA channel.");
}