Expand my Community achievements bar.

SOLVED

Does aem-upload work with external assets and not local files?

Avatar

Level 5

I am trying to use https://github.com/adobe/aem-upload for my project. I was able to test separately from local by keeping as asset in local folder and uploading successfully into cloud aem. But next level, I am trying to pass url instead of local files and run from AppBuilder action. 

 

I realize, this is working only with local files. When I try like 

const targetUrl = 'http://localhost:4502/content/dam/target';

// list of all local files that will be uploaded.
const uploadFiles = [
    {
        fileName: 'file1.jpg', // name of the file as it will appear in AEM
        fileSize: 1024, // total size, in bytes, of the file
        filePath: 'https://www.google.com/publicurl/file1.jpg'
    },
    {
        fileName: 'file2.jpg',
        fileSize: 512,
        filePath: 'https://www.google.com/publicurl/file2.jpg'
    }
];

const upload = new DirectBinary.DirectBinaryUpload();
const options = new DirectBinary.DirectBinaryUploadOptions()
    .withUrl(targetUrl)
    .withUploadFiles(uploadFiles);

pass an absolute url to filePath, this is not working. 

 

Next documentation reads to use local files, OR download the asset as blob and ignore filePath. Is there a working example where you download asset into blob and call withUploadFiles() ?

 

Topics

Topics help categorize Community content and increase your ability to discover relevant content.

1 Accepted Solution

Avatar

Correct answer by
Level 5

After multiple attempts, learning aem-upload CANNOT be used from nodejs backend. It works only for uploading from local files. OR have to build a frontend application and can upload <input type=file> values. But when I had an external (dropbox) url, I am not able to directly call aem-upload. 

withUploadFiles() does support a `blob` type. But accepts <input type=file> value. Now nodejs provides hacky ways to simulate browser input. But I tried different ways and simply didnt work.

 

Instead I was able to directly call Asset Compute microservices. 

 

This is the fix that works from nodejs.

 

import axios from "axios";
import {
  base64Credentials,
  BASIC_AUTH_HEADER
} from "./common.mjs";
import { Core } from "@adobe/aio-sdk";
import { Buffer } from "node:buffer";

const makeUploadRequest = async (
  initiateUploadResponse,
  sourceUrl,
  fileName,
  logger
) => {
  const responseJson = JSON.parse(initiateUploadResponse);
  const arrayNode = responseJson.files;
  if (!arrayNode || arrayNode.length === 0) {
    throw new Error("No file information found in the response");
  }
  const uploadToken = arrayNode[0].uploadToken;
  const mimeType = arrayNode[0].mimeType;
  const binaryPUTUrl = arrayNode[0].uploadURIs[0];
  axios
    .get(sourceUrl, { responseType: "arraybuffer" })
    .then((response) => {
      const fileBytes = Buffer.from(response.data);
      return axios.put(binaryPUTUrl, fileBytes, {
        headers: {
          "Content-Type": "application/octet-stream",
        },
      });
    })
    .then((putResponse) => {
      logger.log("Put response status:", putResponse.status);
      // Handle the putResponse as needed
    })
    .catch((error) => {
      logger.error("An error occurred:", error);
    });
  makeCompleteUploadRequest(uploadToken, mimeType, fileName, logger);
};

const makeCompleteUploadRequest = (uploadToken, mimeType, fileName, logger) => {
  try {
    const form = new FormData();
    form.append("uploadToken", uploadToken);
    form.append("fileName", fileName);
    form.append("createVersion", "true");
    form.append("versionLabel", fileName);
    form.append("mimeType", mimeType);
    axios
      .post(
        "https://author-**-**.adobeaemcloud.com/content/dam/product-content.completeUpload.json",
        form,
        {
          headers: {
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            Authorization: `Basic ${base64Credentials}`,
          },
        }
      );
  } catch (error) {
    logger.error("Error completing upload:", error);
    throw error;
  }
};

const initiateUpload = async (asset, logger) => {
  const data = new FormData();
  data.append("fileName", asset.fileName);
  data.append("fileSize", asset.fileSize);

  const config = {
      method: "post",
      url:"https://author-**-**.adobeaemcloud.com/content/dam/product-content.initiateUpload.json",
      headers: BASIC_AUTH_HEADER,
      data: data,
  };
  try {
    const initiateUpload = await axios.request(config);
    logger.log(`successfully initiated ${initiateUpload}`);
    makeUploadRequest(initiateUpload, asset.sourceUrl, asset.fileName, logger)
  } catch (err) {
    logger.error(`error in uploading assets ${JSON.stringify(err)}`);
  }

};

export const uploadAsset = (assets) => {
  const logger = Core.Logger("main");
  assets.forEach((asset) => {
    initiateUpload(asset, logger);
  });
};

 

View solution in original post

2 Replies

Avatar

Community Advisor

Hi, 

You can pass assets through a REST call if that's what you are asking, you need to get the "asset" from your request body and build the uploadFiles array with it, that's it.  Something like this would work:

 

// req = request
// file = is the actual asset passed through a POST call in this case
let assetToUpload = {
        "fileName": req.file.originalname, 
        "fileSize": req.file.size,
        "versionLabel": "original",
        "blob": req.file.buffer,
        "replace": true
    };

let uploadFiles = [];
uploadFiles.push(assetToUpload);

    const options = new DirectBinary.DirectBinaryUploadOptions()
        .withUrl("yourAEMtargetInstance")
        .withUploadFiles(uploadFiles)
        .withHttpOptions({
            headers: {
                Authorization: `Bearer ${ACCESS_TOKEN}`
            }
        });

Hope this helps.

 

 

 



Esteban Bustamante

Avatar

Correct answer by
Level 5

After multiple attempts, learning aem-upload CANNOT be used from nodejs backend. It works only for uploading from local files. OR have to build a frontend application and can upload <input type=file> values. But when I had an external (dropbox) url, I am not able to directly call aem-upload. 

withUploadFiles() does support a `blob` type. But accepts <input type=file> value. Now nodejs provides hacky ways to simulate browser input. But I tried different ways and simply didnt work.

 

Instead I was able to directly call Asset Compute microservices. 

 

This is the fix that works from nodejs.

 

import axios from "axios";
import {
  base64Credentials,
  BASIC_AUTH_HEADER
} from "./common.mjs";
import { Core } from "@adobe/aio-sdk";
import { Buffer } from "node:buffer";

const makeUploadRequest = async (
  initiateUploadResponse,
  sourceUrl,
  fileName,
  logger
) => {
  const responseJson = JSON.parse(initiateUploadResponse);
  const arrayNode = responseJson.files;
  if (!arrayNode || arrayNode.length === 0) {
    throw new Error("No file information found in the response");
  }
  const uploadToken = arrayNode[0].uploadToken;
  const mimeType = arrayNode[0].mimeType;
  const binaryPUTUrl = arrayNode[0].uploadURIs[0];
  axios
    .get(sourceUrl, { responseType: "arraybuffer" })
    .then((response) => {
      const fileBytes = Buffer.from(response.data);
      return axios.put(binaryPUTUrl, fileBytes, {
        headers: {
          "Content-Type": "application/octet-stream",
        },
      });
    })
    .then((putResponse) => {
      logger.log("Put response status:", putResponse.status);
      // Handle the putResponse as needed
    })
    .catch((error) => {
      logger.error("An error occurred:", error);
    });
  makeCompleteUploadRequest(uploadToken, mimeType, fileName, logger);
};

const makeCompleteUploadRequest = (uploadToken, mimeType, fileName, logger) => {
  try {
    const form = new FormData();
    form.append("uploadToken", uploadToken);
    form.append("fileName", fileName);
    form.append("createVersion", "true");
    form.append("versionLabel", fileName);
    form.append("mimeType", mimeType);
    axios
      .post(
        "https://author-**-**.adobeaemcloud.com/content/dam/product-content.completeUpload.json",
        form,
        {
          headers: {
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            Authorization: `Basic ${base64Credentials}`,
          },
        }
      );
  } catch (error) {
    logger.error("Error completing upload:", error);
    throw error;
  }
};

const initiateUpload = async (asset, logger) => {
  const data = new FormData();
  data.append("fileName", asset.fileName);
  data.append("fileSize", asset.fileSize);

  const config = {
      method: "post",
      url:"https://author-**-**.adobeaemcloud.com/content/dam/product-content.initiateUpload.json",
      headers: BASIC_AUTH_HEADER,
      data: data,
  };
  try {
    const initiateUpload = await axios.request(config);
    logger.log(`successfully initiated ${initiateUpload}`);
    makeUploadRequest(initiateUpload, asset.sourceUrl, asset.fileName, logger)
  } catch (err) {
    logger.error(`error in uploading assets ${JSON.stringify(err)}`);
  }

};

export const uploadAsset = (assets) => {
  const logger = Core.Logger("main");
  assets.forEach((asset) => {
    initiateUpload(asset, logger);
  });
};