Uploading attachments via HTML Bridge

How can I upload images/pdf’s to the app, without using the upload component available? In my use case I want to be able to upload from a HTML bridge component documents that I have generated.

This can be done in 3-4 parts, depending on your use case.

  1. You will need to define the format that you want to use to save the document. This can be a Uint8Array or base64. When saving as a Uint8Array, you will need to convert this to a base64 string.

Example Conversion between Uint8Array and Base64

function converArrayBufferToBase64(buffer) {
    var binary = '';
    var bytes = new Uint8Array(buffer);
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode(bytes[i]);
    }
    return window.btoa(binary);
}
  1. You then need to be able to post this base64 string to your app container. More information can be found here: https://github.com/journeyapps/journey-iframe-client
let _base64String = '<myData>';

const JourneyClient = new JourneyIFrameClient();
JourneyClient.post("saveBase64", _base64String);
  1. Once the application receives the base64 string, you will need to save this into a text field to enable a Cloud Code Task to convert this for you.

App Code:

component.html().on('saveBase64', function(base64String) {
        console.log("Base64 Received");
        view.site_file.base64_string = base64Pdf;
        view.site_file.save();
});

Database Model:

<model name="site_file" label="Site File">
        <field name="archived" label="Archived?" type="boolean" />
        <field name="created_at" label="Created At" type="datetime" />


        <field name="attachment" label="Original Attachment" type="attachment" />
        <field name="base64_string" label="Base64 String" type="text" /> <!-- Helper For Upload -->

        <belongs-to model="user" name="created_by" />  

        <webhook type="update"  receiver="cloudcode" action="convert_base64" />
        <display>{caption}</display>
</model>

Note the webhook being used here to call the Cloud Code task for conversion

  1. You will now need to create a CloudCode task to handle the upload of the document for you
export async function run(event) {

    let _site_file = await DB.site_file.first(event.object.id);

    // Convert the annotated pdf to attachment
    if(_site_file.base64_string) {    
      let _attachment = {
        content: data,
        filename: "Document.pdf"
      }

      await uploadAttachment(_site_file.annotated_base64_string, _site_file, 'attachment');


      // Clear the base64 string
      _site_file.annotated_base64_string = null;
      await _site_file.save();
    }
}

/**
 * Uploads an Attachment to the backend.
 */
async uploadAttachment(attachment, object, field) {

  try {

    let _model = {
        id: object.id,
    }
    _model[field] = { "base64": attachment.content, "filename": attachment.filename };

    let patch_body = {};
    patch_body[object.type.name] = _model;

    console.log(`Uploading Data to [url=${url}/objects/${object.type.name}/${object.id}.json]`);
    let _response = await fetch(`${this.backend.url}/objects/${object.type.name}/${object.id}.json`, {
        headers: {
            'Authorization': this.config.authorization,
            'Content-Type': 'application/json'
            },
            method: 'PATCH',
            body: JSON.stringify(patch_body)
        });

        //Check the response, and throw the appropriate error if required.
        if(_response.status === 401 || _response.status == 403) {
            throw new Error("User not authenticated");
        } else if(!_response.ok) {
            throw _response;
        }

        let _data = await _response.json();
        return _data;
    } catch (error) {
        console.error(error);
        throw error;
    }
}

This should allow you the capability to upload files to the backend with the added bonus of using the offline capabilities of the Journey Apps ecosystem.

4 Likes