Duffer Derek

Current Path : /var/www/api-mk-planner.bitkit.dk/httpdocs/Backend/src/services/api/
Upload File :
Current File : /var/www/api-mk-planner.bitkit.dk/httpdocs/Backend/src/services/api/subtaskComments.js

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