IO-2049 Document delete&move on server side
This commit is contained in:
@@ -13447,6 +13447,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>deleting</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>deleting_cloudinary</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import { useApolloClient, useMutation } from "@apollo/client";
|
||||
import { useApolloClient } from "@apollo/client";
|
||||
import { Button, Form, notification, Popover, Space } from "antd";
|
||||
import axios from "axios";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import {
|
||||
GET_DOC_SIZE_BY_JOB,
|
||||
UPDATE_DOCUMENT,
|
||||
} from "../../graphql/documents.queries";
|
||||
import { GET_DOC_SIZE_BY_JOB } from "../../graphql/documents.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import JobSearchSelect from "../job-search-select/job-search-select.component";
|
||||
|
||||
@@ -23,7 +20,11 @@ export default connect(
|
||||
mapDispatchToProps
|
||||
)(JobsDocumentsGalleryReassign);
|
||||
|
||||
export function JobsDocumentsGalleryReassign({ bodyshop, galleryImages }) {
|
||||
export function JobsDocumentsGalleryReassign({
|
||||
bodyshop,
|
||||
galleryImages,
|
||||
callback,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
|
||||
@@ -36,34 +37,33 @@ export function JobsDocumentsGalleryReassign({ bodyshop, galleryImages }) {
|
||||
const client = useApolloClient();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [updateDocument] = useMutation(UPDATE_DOCUMENT);
|
||||
|
||||
const updateImage = async (i, jobid) => {
|
||||
//Move the cloudinary image
|
||||
// const updateImage = async (i, jobid) => {
|
||||
// //Move the cloudinary image
|
||||
|
||||
//Update it in the database.
|
||||
const result = await updateDocument({
|
||||
variables: {
|
||||
id: i.id,
|
||||
document: {
|
||||
key: i.public_id,
|
||||
jobid: jobid,
|
||||
},
|
||||
},
|
||||
});
|
||||
// //Update it in the database.
|
||||
// const result = await updateDocument({
|
||||
// variables: {
|
||||
// id: i.id,
|
||||
// document: {
|
||||
// key: i.public_id,
|
||||
// jobid: jobid,
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
|
||||
if (!!result.errors) {
|
||||
notification["error"]({
|
||||
message: t("documents.errors.updating", {
|
||||
message: JSON.stringify(result.errors),
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
notification["success"]({
|
||||
message: t("documents.successes.updated"),
|
||||
});
|
||||
}
|
||||
};
|
||||
// if (!!result.errors) {
|
||||
// notification["error"]({
|
||||
// message: t("documents.errors.updating", {
|
||||
// message: JSON.stringify(result.errors),
|
||||
// }),
|
||||
// });
|
||||
// } else {
|
||||
// notification["success"]({
|
||||
// message: t("documents.successes.updated"),
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
|
||||
const handleFinish = async ({ jobid }) => {
|
||||
setLoading(true);
|
||||
@@ -96,6 +96,7 @@ export function JobsDocumentsGalleryReassign({ bodyshop, galleryImages }) {
|
||||
}
|
||||
|
||||
const res = await axios.post("/media/rename", {
|
||||
tojobid: jobid,
|
||||
documents: selectedImages.map((i) => {
|
||||
//Need to check if the current key folder is null, or another job.
|
||||
const currentKeys = i.key.split("/");
|
||||
@@ -110,24 +111,21 @@ export function JobsDocumentsGalleryReassign({ bodyshop, galleryImages }) {
|
||||
};
|
||||
}),
|
||||
});
|
||||
//Add in confirmation & errors.
|
||||
if (callback) callback();
|
||||
|
||||
res.data
|
||||
.filter((d) => d.error)
|
||||
.forEach((d) => {
|
||||
notification["error"]({ message: t("documents.errors.updating") });
|
||||
console.error("Error updating job document", d);
|
||||
if (res.errors) {
|
||||
notification["error"]({
|
||||
message: t("documents.errors.updating", {
|
||||
message: JSON.stringify(res.errors),
|
||||
}),
|
||||
});
|
||||
|
||||
const proms = [];
|
||||
|
||||
res.data
|
||||
.filter((d) => !d.error)
|
||||
.forEach((d) => {
|
||||
proms.push(updateImage(d, jobid));
|
||||
}
|
||||
if (!res.mutationResult?.errors) {
|
||||
notification["success"]({
|
||||
message: t("documents.successes.updated"),
|
||||
});
|
||||
|
||||
await Promise.all(proms);
|
||||
|
||||
}
|
||||
setVisible(false);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
@@ -125,7 +125,10 @@ function JobsDocumentsComponent({
|
||||
deletionCallback={billsCallback || refetch}
|
||||
/>
|
||||
{!billId && (
|
||||
<JobsDocumentsGalleryReassign galleryImages={galleryImages} />
|
||||
<JobsDocumentsGalleryReassign
|
||||
galleryImages={galleryImages}
|
||||
callback={refetch}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
</Col>
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { QuestionCircleOutlined } from "@ant-design/icons";
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { Button, notification, Popconfirm } from "antd";
|
||||
import axios from "axios";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { DELETE_DOCUMENTS } from "../../graphql/documents.queries";
|
||||
//Context: currentUserEmail, bodyshop, jobid, invoiceid
|
||||
|
||||
export default function JobsDocumentsDeleteButton({
|
||||
@@ -13,7 +11,7 @@ export default function JobsDocumentsDeleteButton({
|
||||
deletionCallback,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [deleteDocument] = useMutation(DELETE_DOCUMENTS);
|
||||
|
||||
const imagesToDelete = [
|
||||
...galleryImages.images.filter((image) => image.isSelected),
|
||||
...galleryImages.other.filter((image) => image.isSelected),
|
||||
@@ -27,31 +25,10 @@ export default function JobsDocumentsDeleteButton({
|
||||
ids: imagesToDelete,
|
||||
});
|
||||
|
||||
const successfulDeletes = [];
|
||||
res.data.forEach((resType) => {
|
||||
Object.keys(resType.deleted).forEach((key) => {
|
||||
if (resType.deleted[key] !== "deleted") {
|
||||
notification["error"]({
|
||||
message: t("documents.errors.deleting_cloudinary", {
|
||||
message: JSON.stringify(resType.deleted[key]),
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
successfulDeletes.push(key.replace(/\.[^/.]+$/, ""));
|
||||
}
|
||||
});
|
||||
});
|
||||
const delres = await deleteDocument({
|
||||
variables: {
|
||||
ids: imagesToDelete
|
||||
.filter((i) => successfulDeletes.includes(i.key))
|
||||
.map((i) => i.id),
|
||||
},
|
||||
});
|
||||
if (delres.errors) {
|
||||
if (res.data.error) {
|
||||
notification["error"]({
|
||||
message: t("documents.errors.deleting", {
|
||||
message: JSON.stringify(delres.errors),
|
||||
error: JSON.stringify(res.data.error.response.errors),
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -835,6 +835,7 @@
|
||||
},
|
||||
"errors": {
|
||||
"deletes3": "Error deleting document from storage. ",
|
||||
"deleting": "Error deleting documents {{error}}",
|
||||
"deleting_cloudinary": "Error deleting document from storage. {{message}}",
|
||||
"getpresignurl": "Error obtaining presigned URL for document. {{message}}",
|
||||
"insert": "Unable to upload file. {{message}}",
|
||||
|
||||
@@ -835,6 +835,7 @@
|
||||
},
|
||||
"errors": {
|
||||
"deletes3": "Error al eliminar el documento del almacenamiento.",
|
||||
"deleting": "",
|
||||
"deleting_cloudinary": "",
|
||||
"getpresignurl": "Error al obtener la URL prescrita para el documento. {{message}}",
|
||||
"insert": "Incapaz de cargar el archivo. {{message}}",
|
||||
|
||||
@@ -835,6 +835,7 @@
|
||||
},
|
||||
"errors": {
|
||||
"deletes3": "Erreur lors de la suppression du document du stockage.",
|
||||
"deleting": "",
|
||||
"deleting_cloudinary": "",
|
||||
"getpresignurl": "Erreur lors de l'obtention de l'URL présignée pour le document. {{message}}",
|
||||
"insert": "Incapable de télécharger le fichier. {{message}}",
|
||||
|
||||
@@ -1611,3 +1611,13 @@ exports.INSERT_EMAIL_AUDIT = `mutation INSERT_EMAIL_AUDIT($email: email_audit_tr
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
exports.DELETE_MEDIA_DOCUMENTS = `
|
||||
mutation DELETE_DOCUMENTS($ids: [uuid!]!) {
|
||||
delete_documents(where: { id: { _in: $ids } }) {
|
||||
returning {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
const path = require("path");
|
||||
const _ = require("lodash");
|
||||
const logger = require("../utils/logger");
|
||||
const client = require("../graphql-client/graphql-client").client;
|
||||
const queries = require("../graphql-client/queries");
|
||||
|
||||
require("dotenv").config({
|
||||
path: path.resolve(
|
||||
@@ -69,11 +71,38 @@ exports.deleteFiles = async (req, res) => {
|
||||
);
|
||||
}
|
||||
|
||||
res.send(returns);
|
||||
// Delete it on apollo.
|
||||
const successfulDeletes = [];
|
||||
returns.forEach((resType) => {
|
||||
Object.keys(resType.deleted).forEach((key) => {
|
||||
if (
|
||||
resType.deleted[key] === "deleted" ||
|
||||
resType.deleted[key] === "not_found"
|
||||
) {
|
||||
successfulDeletes.push(key.replace(/\.[^/.]+$/, ""));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
const result = await client.request(queries.DELETE_MEDIA_DOCUMENTS, {
|
||||
ids: ids
|
||||
.filter((i) => successfulDeletes.includes(i.key))
|
||||
.map((i) => i.id),
|
||||
});
|
||||
|
||||
res.send({ returns, result });
|
||||
} catch (error) {
|
||||
logger.log("media-delete-error", "ERROR", req.user.email, null, [
|
||||
{ ids, error: error.message || JSON.stringify(error) },
|
||||
]);
|
||||
|
||||
res.json({ error });
|
||||
}
|
||||
};
|
||||
|
||||
exports.renameKeys = async (req, res) => {
|
||||
const { documents } = req.body;
|
||||
const { documents, tojobid } = req.body;
|
||||
logger.log("media-bulk-rename", "DEBUG", req.user.email, null, documents);
|
||||
|
||||
const proms = [];
|
||||
@@ -98,8 +127,37 @@ exports.renameKeys = async (req, res) => {
|
||||
let result;
|
||||
|
||||
result = await Promise.all(proms);
|
||||
const errors = [];
|
||||
result
|
||||
.filter((d) => d.error)
|
||||
.forEach((d) => {
|
||||
errors.push(d);
|
||||
});
|
||||
|
||||
res.send(result);
|
||||
let mutations = "";
|
||||
|
||||
result
|
||||
.filter((d) => !d.error)
|
||||
.forEach((d, idx) => {
|
||||
//Create mutation text
|
||||
|
||||
mutations =
|
||||
mutations +
|
||||
`
|
||||
update_doc${idx}:update_documents_by_pk(pk_columns: { id: "${d.id}" }, _set: {key: "${d.public_id}", jobid: "${tojobid}"}){
|
||||
id
|
||||
}
|
||||
`;
|
||||
});
|
||||
|
||||
if (mutations !== "") {
|
||||
const mutationResult = await client.request(`mutation {
|
||||
${mutations}
|
||||
}`);
|
||||
res.json({ errors, mutationResult });
|
||||
} else {
|
||||
res.json({ errors: "No images were succesfully moved on remote server. " });
|
||||
}
|
||||
};
|
||||
|
||||
//Also needs to be updated in upload utility and mobile app.
|
||||
|
||||
Reference in New Issue
Block a user