Hello Everyone,

I have a Requirement to upload Attachment and Some header fields of Custom Object to another Application Through API. I m able to get header data from a Custom Webservice but not sure how to get attachment that can be uploaded to another Application. 

Like 0

Like

4 comments

Hi!

 

You can write a custom web service in Creatio that retrieves the required attachment(s) from the custom object, formats the data appropriately, and sends it to the other application's API using HTTP requests. Alternatively, you could look into using a pre-built integration tool or middleware solution that can facilitate the transfer of data between applications in the marketplace. As an example, if you would intend to use DocuWare for your uploaded attachments -https://marketplace.creatio.com/app/docuware-connector-creatio.

 

Hope this info was helpful.

Hi! 

 

I would like to add that you might find the relevant information about the API file attachments on this page of the Academy - https://academy.creatio.com/docs/user/setup_and_administration/base_int…

 

We will be glad to help with any other questions.

Hello Everyone ,

Well I tried Creating WebService that can get and post the Data in Attachment Section but When i Try to Get the Data Using Record id its not getting it. Can you please Advise .

Screenshot of Postman is Attached and the Code of WebService

Code : 





 

namespace Terrasoft.Configuration.UsrCustomConfigurationServiceNamespace

{

using System;

using System.ServiceModel;

using System.ServiceModel.Web;

using System.ServiceModel.Activation;

using Terrasoft.Core;

using Terrasoft.Web.Common;

using Terrasoft.Core.Entities;

using System.Collections.Generic;



[ServiceContract]

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

public class UsrCustomConfigurationService : BaseService

{

    /* The method that creates a new record in the SysFile entity. */

    [OperationContract]

[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,

    ResponseFormat = WebMessageFormat.Json)]

public string CreateSysFileRecord(string data, string fileGroup, string id, string name, int size,

    string sysFileStorage, string type, string recordId, string recordSchemaName)

{

    UserConnection userConnection = GetUserConnection();

    EntitySchemaManager entitySchemaManager = userConnection.EntitySchemaManager;

    EntitySchema entitySchema = entitySchemaManager.GetInstanceByName("SysFile");

    Entity entity = entitySchema.CreateEntity(userConnection);

    entity.SetDefColumnValues();

    entity.SetColumnValue("Data", Convert.FromBase64String(data));

    entity.SetColumnValue("FileGroup", new Guid(fileGroup));

    entity.SetColumnValue("Id", new Guid(id));

    entity.SetColumnValue("Name", name);

    entity.SetColumnValue("Size", size);

    entity.SetColumnValue("SysFileStorage", new Guid(sysFileStorage));

    entity.SetColumnValue("Type", new Guid(type));

    entity.SetColumnValue("RecordId", new Guid(recordId));

    entity.SetColumnValue("RecordSchemaName", recordSchemaName);

    if (!entity.Save())

    {

        throw new Exception("Failed to create SysFile record");

    }

    return entity.PrimaryColumnValue.ToString();

}

/* The method that retrieves a SysFile record by ID. */

[OperationContract]

[WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,

ResponseFormat = WebMessageFormat.Json)]

public Dictionary<string, object> GetSysFileById(string id) {

    /* The default result. */

    var result = new Dictionary<string, object>();

    /* The EntitySchemaQuery instance that accesses the SysFile database table. */

    var esq = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "SysFile");

    /* Add columns to the query. */

    var colId = esq.AddColumn("Id");

    var colName = esq.AddColumn("Name");

    var colData = esq.AddColumn("Data");

    var colSize = esq.AddColumn("Size");

    var colFileGroup = esq.AddColumn("FileGroup");

    var colSysFileStorage = esq.AddColumn("SysFileStorage");

    var colType = esq.AddColumn("Type");

    var colRecordId = esq.AddColumn("RecordId");

    var colRecordSchemaName = esq.AddColumn("RecordSchemaName");

    /* Filter the query data. */

    var esqFilter = esq.CreateFilterWithParameters(FilterComparisonType.Equal, "Id", id);

    esq.Filters.Add(esqFilter);

    /* Retrieve the query results. */

    var entities = esq.GetEntityCollection(UserConnection);

    /* If the service receives data. */

    if (entities.Count > 0)

    {

        var entity = entities[0];

        /* Add the values of the record fields to the result dictionary. */

        result.Add("Id", entity.GetTypedColumnValue<Guid>(colId.Name));

        result.Add("Name", entity.GetTypedColumnValue<string>(colName.Name));

        result.Add("Data", entity.GetTypedColumnValue<byte[]>(colData.Name));

        result.Add("Size", entity.GetTypedColumnValue<int>(colSize.Name));

        result.Add("FileGroup", entity.GetTypedColumnValue<Guid>(colFileGroup.Name));

        result.Add("SysFileStorage", entity.GetTypedColumnValue<Guid>(colSysFileStorage.Name));

        result.Add("Type", entity.GetTypedColumnValue<Guid>(colType.Name));

        result.Add("RecordId", entity.GetTypedColumnValue<Guid>(colRecordId.Name));

        result.Add("RecordSchemaName", entity.GetTypedColumnValue<string>(colRecordSchemaName.Name));

    }

    // Return the results.

    return result;

}

}

}

Show all comments

Hello Creatio Community !

I want to resctrict the file formats uploaded to creatio. For example I want to allow uploading only pdf,word, excel, jpeg files and restrict Json files.

How is this configuration done ?

Like 0

Like

2 comments
Best reply

Hello Petrika,

 

You can refer the Secure file upload academy article to achieve your needs.

 

Regards,

Sourav Kumar samal

Hello Petrika,

 

You can refer the Secure file upload academy article to achieve your needs.

 

Regards,

Sourav Kumar samal

Sourav Kumar Samal,

Thank you . It solved my issue.

Best Regards

Show all comments

Hello

I am making a small python application that can upload and attach files to creatio.

Connection and authentication to creatio is ok.

I can use /0/odata to get value from creatio (in the sam script with the same session).

 

I get a 403 when using  /0/rest/FileApiService/UploadFile.

Here is my request uri that I send via a Post

https://CreatioURL/0/rest/FileApiService/UploadFile?fileapi165097538874…

 

My request with headers:

POST /0/rest/FileApiService/UploadFile?fileapi165097538874218&totalFileLength=106789&fileId=a00a2990-87d3-4cc8-a96a-465243dfc6ba&mimeType=application%2Fpdf&columnName=Data&fileName=INV-10699-SAF.pdf&parentColumnName=Invoice&parentColumnValue=ff4a0279-1e86-4983-918b-fefd28483df3&entitySchemaName=InvoiceFile HTTP/1.1\r\nHost: creatiosite.com\r\nUser-Agent: python-requests/2.27.1\r\nAccept-Encoding: gzip, deflate, br\r\nAccept: application/json\r\nConnection: keep-alive\r\nForceUseSession: true\r\nContent-Type: application/pdf\r\nCookie: .ASPXAUTH=; BPMCSRF=zaZ0DPSfWLLw8otH5Vzwu.; BPMLOADER=klb0towmoqgvkw0pn4n5hzdy; UserName=97|110|116|111|105|110|101|46|103|105|108|108|105|101|114|111|110\r\nContent-Length: 106789\r\n\r\n'

 

 

 

Like 0

Like

8 comments
Best reply

Hello Antoine,

It's not enough to include the cookies from the original request. You have to also read the value of the BPMCSRF cookie and add to header as well as "BPMCSRF" (it's looking for this specific header, not a cookie with this value). Does that make sense?

Basically, after the authentication request, copy the value of the BPMCSRF cookie and add a BPMCSRF header with that cookie value.

Ryan

Hello,

 

Mostly seems that there is no separate BPMSCRF header in the request you are sending (it's the most common issue for 403 error in Postman). Try adding it as below:

Best regards,

Oscar

Hello

Thank you for your answer, I m sending the request via a "session" object in python. Creating the object session when authenticating so it keeps all cookies. You can see in my request header that the BPMCSRF parameter is present in the header cookie. Making a "get" request to odata with the same session works. Meaning the BPMSCRF value is correctly received by Creatio.

I suspect a bad particular header or request parameter!

For example, what is the purpose of the first request parameter:fileapi165097538874218 ?

I got this one by capturing a request with fiddler.

Thank you

Hello Antoine,

It's not enough to include the cookies from the original request. You have to also read the value of the BPMCSRF cookie and add to header as well as "BPMCSRF" (it's looking for this specific header, not a cookie with this value). Does that make sense?

Basically, after the authentication request, copy the value of the BPMCSRF cookie and add a BPMCSRF header with that cookie value.

Ryan

Ryan Farley,

Hello

Thank you for your answer

Now I get reply: 'HTTP/1.1 200 OK\r\n' response.

But my file is not beeing created in Creatio. 

Do you know if I have to create the object prior to uploading the file content with the file api (/0/rest/FileApiService/UploadFile)?

Thank you 

 

Antoine Gilliéron,

Looks like you'te validating fine now, but the request is missing something.

When I do it, I include the following (looks like you have these accounted for, but just listing for something to check):

 

Headers:

  1. Content-Disposition = attachment; filename=TheFile.docx
  2. Content-Length = size in bytes
  3. Content-Range = bytes 0-{size in bytes - 1}/{size in bytes}

Query String Parameters:

  1. totalFileLength = size in bytes
  2. fileId = new guid id value
  3. columnName = "Data"
  4. fileName = "TheFile.docx"
  5. parentColumnName = "Invoice"
  6. parentColumnValue = the invoice Id
  7. entitySchemaName = "InvocieFile"

Request Body:

  1. "application/octet-stream" = the file bytes

Ryan

Antoine Gilliéron,

Also, to confirm:

Do you know if I have to create the object prior to uploading the file content with the file api 

No, there's no need to create the record separately first.

Hello Ryan

I was missing some of the headers and the correct Content-Type.

Now everything works as expected.

Thank you so much for your help.

I am trying to make the same request, but it returns 200 but with a json saying it gave an error.

{
    "errorInfo": {
        "errorCode": "FileNotFoundByLocatorException",
        "message": "File not found by locator 'Terrasoft.File.EntityFileLocatorEntitySchemaName=ActivityFile, RecordId=2b796759-8846-41b9-9c2b-cfd428493b3c'",
        "stackTrace": "   at Terrasoft.File.File`2.get_FileMetadata()\r\n   at Terrasoft.File.File`2.InitContentStorageId()\r\n   at Terrasoft.File.File`2.&lt;WriteAsync&gt;d__45.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at Terrasoft.Common.Threading.AsyncPump.Run(Func`1 asyncMethod)\r\n   at Terrasoft.Configuration.FileUpload.FileUploader.Upload(IFileUploadConfig fileUploadConfig)\r\n   at Terrasoft.Configuration.FileUpload.FileUploader.UploadFile(IFileUploadConfig fileUploadInfoConfig)\r\n   at Terrasoft.Configuration.FileUpload.FileUploader.UploadFile(IFileUploadInfo fileUploadInfo, Boolean isSetCustomColumns)\r\n   at Terrasoft.Configuration.FileApiService.UploadFile(Stream fileContent)"
    },
    "success": false,
    "nextPrcElReady": false,
    "queryId": null,
    "responseStatus": {
        "ErrorCode": "FileNotFoundByLocatorException",
        "Message": "File not found by locator 'Terrasoft.File.EntityFileLocatorEntitySchemaName=ActivityFile, RecordId=2b796759-8846-41b9-9c2b-cfd428493b3c'",
        "StackTrace": "   at Terrasoft.File.File`2.get_FileMetadata()\r\n   at Terrasoft.File.File`2.InitContentStorageId()\r\n   at Terrasoft.File.File`2.&lt;WriteAsync&gt;d__45.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at Terrasoft.Common.Threading.AsyncPump.Run(Func`1 asyncMethod)\r\n   at Terrasoft.Configuration.FileUpload.FileUploader.Upload(IFileUploadConfig fileUploadConfig)\r\n   at Terrasoft.Configuration.FileUpload.FileUploader.UploadFile(IFileUploadConfig fileUploadInfoConfig)\r\n   at Terrasoft.Configuration.FileUpload.FileUploader.UploadFile(IFileUploadInfo fileUploadInfo, Boolean isSetCustomColumns)\r\n   at Terrasoft.Configuration.FileApiService.UploadFile(Stream fileContent)",
        "Errors": null,
        "Meta": null
    },
    "rowsAffected": -1
}

I have added all the header and parameters correctly and also the file in the body.

 

Show all comments

Hi Community,

I am trying to make a request from Creatio to the HTTP REST API Endpoints. |Where File should be added to the API request. 

Is there any way to work with the File type request Parameter in Rest API from Creatio? If yes, please suggest to me how I can achieve this.

 

An example of an API call from Postman is something like as per below :

 

Like 0

Like

3 comments

Hi Patrik,

 

To successfully upload an image you need to make sure that "WebDav publishing" feature is disabled in Windows features of the IIS server (can be found at "World wide web services" -> "Common HTTP Features" -> "WebDAVPublishing"):

Once done you need to perform the following steps:

 

1) Create a POST request to https://app_root_URL/0/odata/SysImage with the JSON raw body with the following content:

{
    "Name": "scr_NewContactPhoto.png",
    "Id": "330006E1-CA4E-4502-A9EC-E54D922D2C01",
    "MimeType": "image/png"
}

330006E1-CA4E-4502-A9EC-E54D922D2C01 should be a random unique identifier. This request will create a record in the SysImage table and the response should be similar to the below:

{
    "@odata.context": "https://app_root_URL/0/odata/$metadata#SysImage/$entity",
    "Id": "330006e1-ca4e-4502-a9ec-e54d922d2c01",
    "CreatedOn": "2021-09-30T10:24:26.830457Z",
    "CreatedById": "410006e1-ca4e-4502-a9ec-e54d922d2c00",
    "ModifiedOn": "2021-09-30T10:24:26.830457Z",
    "ModifiedById": "410006e1-ca4e-4502-a9ec-e54d922d2c00",
    "ProcessListeners": 0,
    "UploadedOn": "0001-01-01T00:00:00Z",
    "Name": "scr_NewContactPhoto.png",
    "Data@odata.mediaEditLink": "SysImage(330006e1-ca4e-4502-a9ec-e54d922d2c01)/Data",
    "Data@odata.mediaReadLink": "SysImage(330006e1-ca4e-4502-a9ec-e54d922d2c01)/Data",
    "Data@odata.mediaContentType": "application/octet-stream",
    "MimeType": "image/png",
    "HasRef": false,
    "PreviewData@odata.mediaEditLink": "SysImage(330006e1-ca4e-4502-a9ec-e54d922d2c01)/PreviewData",
    "PreviewData@odata.mediaReadLink": "SysImage(330006e1-ca4e-4502-a9ec-e54d922d2c01)/PreviewData",
    "PreviewData@odata.mediaContentType": "application/octet-stream"
}

2) Create a PUT request to https://app_root_URL/0/odata/SysImage(330006e1-ca4e-4502-a9ec-e54d922d2c01)/Data with the binary body and select an image there:

Once executed the response will be 200OK.

 

And after that we can perform a GET request to check the result:

Please also note that BPMCSRF cookie should be always in headers:

Best regards,

Oscar

Hi Oscar,

Thanks for the Guidance, But I want to make an API call from Creatio itself ( Using Web-Service / Script Task ), not from Postman

 

Could you guide me on that? 

Hi Pratik,

 

Please see examples here https://academy.creatio.com/docs/developer/integrations_and_api/data_se…

 

Best regards,

Oscar

Show all comments

Hello,

I have added a number column to the OpportunityFile object, and I have two separate File details for uploading to the same Opportunity. I would like each detail so set my new column to a different value (numbers 1 or 2). How can this be achieved?

Like 0

Like

1 comments

Hello Jordan,

 

There should be two different schemas for these two details that are using the same object. To achieve your task you need to add this method two both your details schemas:

 

methods: {

            save: function() {

                this.callParent(arguments);

                this.setInteger();

            },

            setInteger: function() {

            this.set("UsrInteger1", 2);

            }

        },

 

and replace UsrInteger1 with the name of your integer column from the object and specify the value of 1 or 2 in this part

 

this.set("UsrInteger1", 2);

 

for each detail schema separately. As a result, each time you add the file to each detail your integer column will be populated with the correct integer value.

 

Best regards,

Oscar

Show all comments

Hi Team

I created a Node.js script to upload attachments using FileApiService.

Here is my script:

var axios = require('axios');

var fs = require('fs');

establish_connection();

 

async function establish_connection()

{

        axios.post('https://company_name.bpmonline.com/ServiceModel/AuthService.svc/Login',

        {

            "UserName":"xxxxxxx",

            "UserPassword":"xxxxxxxxxxx"

            

        }).then (function (response){

            console.log('Imported credentials cookie from BPM Online!')

            c=response.headers['set-cookie']

            var bpm_loader=c[0]

            bpm_loader = bpm_loader.replace('BPMLOADER=','')

            bpm_loader=bpm_loader.split(';')[0]

            var aspx_auth=c[1]

            aspx_auth = aspx_auth.replace('.ASPXAUTH=','')

            aspx_auth=aspx_auth.split(';')[0]

            var bpm_csrf=c[2]

            bpm_csrf = bpm_csrf.replace('BPMCSRF=','')

            bpm_csrf=bpm_csrf.split(';')[0]

            var user_name=c[3]

            user_name = user_name.replace('UserName=','')

            user_name=user_name.split(';')[0]

            var auth = 'BPMLOADER='+bpm_loader+'; .ASPXAUTH='+aspx_auth+'; BPMCSRF='+bpm_csrf+'; UserName='+user_name+';';

            console.log('Authentication Successful!')

            upload_attachments(auth,bpm_csrf)

        }).catch(error => {

            console.log(error)

        })

}

async function upload_attachments(auth,bpm_csrf) {

  let myPdf = fs.readFileSync("./file_name.pdf");

  let myData = myPdf.toString("base64");

 

  let myBody = {

    Name: "test.pdf",

    Data: myData,

    TypeId: '529bc2f8-0ee0-df11-971b-001d60e938c6',//This indicates that the type of the attachment is file

    Version: "1",

    Usr_reference_column_id: 'xxxxxguid_of_the_record_xxxxxxxx'

  };

 

  let options = {

    method: "POST",

    url: 'https://company_name.bpmonline.com/0/rest/FileApiService/Upload',

    headers: {

        "fileapi14998570381414":"",

      "cache-control": "no-cache",

      "Accept-Encoding": "gzip, deflate",

      "Cache-Control": "no-cache",

      Accept: "*/*",

      "Content-Type": "application/json;odata=verbose",

      Cookie:auth,

      BPMCSRF:bpm_csrf,

      "entitySchemaName":"Usr_id_of_the_file_section"

    },

    body: myBody,

    json: true

  };

 

  request(options, function(error, response, body) {

    if(!error)

    {

        console.log('Success!')

        console.log(response)

    }

    else

    {

        console.log('Failed!')

        console.log(error)

    }

  });

}

 

References: 

1. https://community.bpmonline.com/questions/sending-blob-file-node

2. https://community.bpmonline.com/questions/upload-files-case

3. https://community.bpmonline.com/questions/how-upload-attachments-odata

4. https://community.terrasoft.ru/questions/realizacia-peredaci-pdf-dokumenta-po-protokolu-odata-s-ispolzovaniem-http-zaprosov

5. https://community.terrasoft.ru/questions/fileapiservice-zagruzka-dokumenta-v-faily-i-primecania-crm-sistemy

 

I am able to establish connection (Authorization is successful) and getting SUCCESS for the attachment. But in the response, I am receiving 'Request Error'.

 

Questions:

1. Is my URL correct?

2. Is the way I specified file section name correct?

3. Do I need to add/delete/change my request body?

4. Do I need to create a MODULE in ADVANCED SETTINGS?

 

NOTE: I am using BPM'Online Studio.

Like 0

Like

1 comments

It's hard to say how it should be done on Node.js. However, there is an easy way to find if your request is correct. Please install "telerik fiddler" and catch the request that you send to bpm'online. For example, send file.jpg. Then open bpm'online and add the same file for example to a contact. Catch the request with fiddler too. Then compare those two requests. Your task is to create a functionality that will send exactly the same request. 

If you need an example on JS, please put a break point into the "upload" method in the ConfigurationFileApi module (in a browser) and add a file to a contact. You'll see how bpm'online generates the request. Please try to do the same on Node.js. 

Show all comments

The command of "Aplana. Business solutions" presents a new file manager for bpm'online.

The new features of the add-on includes:

  • addition of a file manager module to a page of any system section using the page editor;
  • managing the file directory and set access rights to it;
  • loading, moving and deleting one file as well as a collection of files in one click;
  • setting the type of file storage mentioning the local server or database;
  • storage of multiple versions of files;
  • preview file images in the window straight on the page by double-clicking;
  • addition to the archive and unpack the zip-archive;
  • play audio files;
  • play video files;
  • controlling the access to file directories.

 

For more information please check the Marketplace: https://marketplace.bpmonline.com/app/file-manager-bpmonline

Like 0

Like

Share

0 comments
Show all comments