Duffer Derek
import axios from "axios";
import FormData from "form-data";
import fs from "fs";
import { dirname } from "path";
import Podio from "@phasesdk/api-client-for-podio";
import { Op } from "sequelize";
import { fileURLToPath } from "url";
import Log from "../../configs/logger.js";
import files from "../../database/models/files.js";
import subTasksComments from "../../database/models/subTasksComments.js";
import tasks from "../../database/models/tasks.js";
import User from "../../database/models/users.js";
import { extensionToMime } from "../../utils/helper.util.js";
import { uploadFile } from "../fileUpload.js";
import { appAuthentication } from "../podio/podio.js";
import { item } from "./tasks.js";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const filePath = `${__dirname}/../../storage/public/files`;
let podioFileIds = [];
export const insertOrUpdateComments = async (
req,
deletion,
user_name,
date
) => {
try {
const { sub_task_id, item_id } = req.body;
await loopMultipleFiles(req, sub_task_id, item_id);
Log.info("All files processed successfully", podioFileIds);
setTimeout(async () => {
await udpatePodioFiles(sub_task_id, item_id, deletion, user_name, date);
}, 2000);
} catch (error) {
Log.error(error);
}
};
export const deletePartnerFiles = async (fileIds) => {
try {
Log.info("deletion of files ");
await files.destroy({
where: {
file_id: fileIds,
keyword: "partner_image",
},
});
} catch (error) {
Log.error(error);
}
};
const loopMultipleFiles = (req, sub_task_id, item_id) => {
const uploadPromises = req.files.map(async (file, index) => {
Log.info("proccesing on", file);
await fileUplaod(file, item_id, sub_task_id);
});
return Promise.all(uploadPromises);
};
const fileUplaod = async (file, item_id, sub_task_id) => {
try {
if (file) {
const lastDotIndex = file.originalname.lastIndexOf(".");
const extension = file.originalname.substring(lastDotIndex);
const randomString = Math.random().toString(36).substring(2, 10);
// Extract the filename without extension
const filenameWithoutExtension = file.originalname.substring(
0,
lastDotIndex
);
// Concatenate the filename with random string and extension
const fileName = `${filenameWithoutExtension}_${randomString}${extension}`;
const path = filePath + `/${item_id}/${fileName}`;
await uploadFile(path, file);
Log.info(fileName + "Uploading to podio");
let podioFileId = await podioFileUpload(path, fileName);
Log.info(fileName + "Uploaded to podio");
let insertFile = {
item_id: sub_task_id,
keyword: "partner_image",
filename: `/${item_id}/${fileName}`,
file_id: podioFileId,
};
Log.info("Insert file", insertFile);
await insertFiles(insertFile);
podioFileIds.push(podioFileId);
}
} catch (error) {
Log.error(error);
}
};
const insertFiles = async (data) => {
try {
let insertData = {
item_id: data.item_id,
keyword: data.keyword,
filename: data.filename,
file_id: data.file_id,
};
await files.create(insertData);
} catch (error) {
Log.error(error);
}
};
const podioFileUpload = async (filePath, fileName) => {
try {
const auth = await appAuthentication(
process.env.FILE_APP_ID,
process.env.FILE_APP_TOKEN
);
let data = new FormData();
data.append("source", fs.createReadStream(filePath));
data.append("filename", fileName);
const config = {
method: "post",
url: process.env.PODIO_API_URL + "file/",
headers: {
Authorization: `Bearer ${auth.access_token}`,
"Content-Type": "multipart/form-data",
...data.getHeaders(),
},
data: data,
};
try {
let res = await axios(config);
return res.data.file_id;
} catch (err) {
Log.error(err);
return 0;
}
} catch (err) {
Log.error(err);
return 0;
}
};
/**
* Update Podio item with new file IDs.
* @param {Array} fileIds - Array of file IDs to update the Podio item with.
* @param {number} item_id - ID of the Podio item to update.
*/
const udpatePodioFileItem = async (fileIds, videoFileIds, item_id) => {
try {
let attributes = {
fields: {
billeder: fileIds,
},
file_ids: videoFileIds,
};
const auth = await appAuthentication(
process.env.FILE_APP_ID,
process.env.FILE_APP_TOKEN
);
let res = await Podio.api.item(auth).update(item_id, attributes);
Log.info("podio file item updated");
podioFileIds = [];
} catch (error) {
Log.error(error);
}
};
export const deletePodioItemFiles = async (itemId) => {
try {
const auth = await appAuthentication(
process.env.FILE_APP_ID,
process.env.FILE_APP_TOKEN
);
let res = await Podio.api.item(auth).delete(itemId);
Log.info("podio file item has been deleted");
} catch (error) {
Log.error(error);
}
};
export const deleteComments = async (ids, sub_task_id) => {
try {
const commentIds = await subTasksComments.findAll({
attributes: ["id", "file_item_id"],
where: {
id: {
[Op.notIn]: ids,
},
sub_task_id: sub_task_id,
},
});
if (commentIds.length > 0) {
let fileIitemId = null;
commentIds.forEach(async (commentId) => {
// partner deleted all images
fileIitemId = commentId.file_item_id;
await subTasksComments.destroy({
where: {
id: commentId.id,
},
});
await files.destroy({
where: { item_id: commentId.id, keyword: "partner_image" },
});
});
if (ids[0] == 0 && fileIitemId) {
Log.info(
"in the fun ----------- if (ids.length == 0 && fileIitemId) { "
);
deletePodioFile(fileIitemId);
}
}
return;
} catch (error) {
Log.error(error);
}
};
export const udpatePodioFiles = async (
subTaskId,
taskId,
deletion,
user_name,
date
) => {
try {
const allFiles = await files.findAll({
attributes: ["podio_item_id", "file_id", "filename"],
where: {
item_id: subTaskId,
},
});
let fileIds = [];
let videoFileIds = [];
let fileItemId = "";
if (allFiles.length > 0) {
let filteredFiles = [];
let filesForDeletion = [];
let deletedItemId = "";
if (deletion != undefined) {
const formattedDeletionIds = deletion.map((str) => parseInt(str));
filteredFiles = allFiles.filter(
(file) => !formattedDeletionIds.includes(file.file_id)
);
//for all existing files deletd and add new files not need to create new item in podio
filesForDeletion = allFiles.filter((file) =>
formattedDeletionIds.includes(file.file_id)
);
deletedItemId = filesForDeletion[0].dataValues.podio_item_id;
await deletePartnerFiles(deletion);
} else {
filteredFiles = allFiles;
}
if (filteredFiles.length > 0) {
if (deletedItemId !== undefined) {
fileItemId = deletedItemId;
}
filteredFiles.forEach((file) => {
let type = extensionToMime[file.filename.match(/\.([^.]+)$/)[1]];
if (file.dataValues.file_id) {
if (type.includes("video/")) {
videoFileIds.push(file.dataValues.file_id);
} else {
fileIds.push(file.dataValues.file_id);
}
}
if (file.dataValues.podio_item_id !== null) {
fileItemId = file.dataValues.podio_item_id;
}
});
if (fileItemId !== "") {
await udpatePodioFileItem(fileIds, videoFileIds, fileItemId);
let attr = { podio_item_id: fileItemId };
await updateFilesTable(attr, subTaskId);
} else if (fileItemId === "") {
if (fileIds.length > 0 || videoFileIds.length > 0) {
const response = await createPodioFileItem(
fileIds,
videoFileIds,
taskId,
user_name,
date
);
let attr = { podio_item_id: response };
await updateFilesTable(attr, subTaskId);
}
}
} else {
//all files are empty if any item is presnet in podio then delete
const podioItemId = allFiles[0].dataValues.podio_item_id;
await deletePodioItemFiles(podioItemId);
Log.info("deletion completd of ", podioItemId);
}
}
return;
} catch (error) {
Log.error(error);
}
};
export const getPartnerFiles = async (subTaskId) => {
try {
const partnerFiles = await files.findAll({
attributes: [
"item_id",
"file_id",
"keyword",
"filename",
"podio_item_id",
],
where: { item_id: subTaskId, keyword: "partner_image" },
});
let formatedPartnerFiles = partnerFiles.map((partnerFile) => {
return {
file_id: partnerFile.file_id,
name: partnerFile.filename.split("/").pop(),
item_id: partnerFile.item_id,
keyword: partnerFile.keyword,
objectURL: process.env.APP_BASE_URL + "/files" + partnerFile.filename,
type: extensionToMime[partnerFile.filename.match(/\.([^.]+)$/)[1]],
};
});
return formatedPartnerFiles;
} catch (error) {
Log.error(error);
}
};
export const getSubtaskComments = async (subTaskId) => {
try {
const comments = await subTasksComments.findAll({
where: { sub_task_id: subTaskId },
include: {
model: files,
attributes: ["file_id", "keyword", "filename", "item_id"],
},
});
let formatedComments = [
{
previewUrl: "",
inputValue: "",
fileError: false,
noteError: false,
addButton: true,
id: 0,
},
];
let countOfComments = comments.length;
comments?.forEach((comment, index) => {
let addButton = false;
let newComment = {
previewUrl:
process.env.APP_BASE_URL + "files/" + comment.files[0].filename,
inputValue: comment.comments,
fileError: false,
noteError: false,
addButton: addButton,
isNew: false,
id: comment.id,
};
formatedComments.push(newComment);
});
return formatedComments;
} catch (error) {
Log.error(error);
}
};
export const addPodioComment = async (itemId, comment) => {
try {
let mention = "";
const task = await tasks.findOne({
where: { item_id: itemId },
});
if (task.service_manager_id > 0) {
const serviceManager = await User.findOne({
where: { item_id: task.service_manager_id },
});
mention = ` @[${serviceManager.name}](user:${task.service_manager_id})`;
}
const auth = await appAuthentication(
process.env.TASK_APP_ID,
process.env.TASK_APP_TOKEN
);
let attributes = {
value: comment + mention,
};
Log.info(`adding comment to ${itemId}`, attributes);
await Podio.api.comment(auth).create("item", itemId, attributes);
return;
} catch (error) {
Log.info(error);
}
};
const createPodioFileItem = async (
fileIds,
videoFileIds,
itemId,
user_name,
date
) => {
try {
let itemDetails = await item(itemId);
Log.info("item detalis", itemDetails);
let customerAddress =
itemDetails.customer_address != null
? itemDetails.customer_address.replace(/<[^>]*>/g, "") + "-"
: "";
let customerName = itemDetails.customer_first_name + "-";
let phone =
itemDetails.customer_phone_number != null
? itemDetails.customer_phone_number + "-"
: "";
let name =
user_name != null && user_name != undefined ? user_name + "-" : "";
let title = customerName + phone + customerAddress + name + date;
Log.info("title", title);
let attributes = {
fields: {
titel: title,
status: [1],
billeder: fileIds,
henvendelse: [parseInt(itemId)],
},
file_ids: videoFileIds,
};
const auth = await appAuthentication(
process.env.FILE_APP_ID,
process.env.FILE_APP_TOKEN
);
let res = await Podio.api
.item(auth)
.create(process.env.FILE_APP_ID, attributes);
Log.info(res.data.item_id);
return res.data.item_id;
} catch (error) {
Log.error(error);
}
};
const updateFilesTable = async (attr, subTaskId) => {
try {
const result = await files.update(attr, {
where: { item_id: subTaskId },
});
} catch (error) {
Log.error("Error updating files table ", error);
}
};
const deletePodioFile = async (itemId) => {
try {
Log.info("in the fun ----------- deletePodioFile(itemId)");
const auth = await appAuthentication(
process.env.FILE_APP_ID,
process.env.FILE_APP_TOKEN
);
await Podio.api.item(auth).delete(itemId);
} catch (error) {
Log.error(error);
}
};
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists