Hi,
I am trying to make a php script to add thousands of pictures to existing contacts bpm.
Support helped me already and told that I should create (POST) a new entry in SysImageCollection with json {id: guid, name: guid}.
Then upload the image binary (base64, zipped or not, I tried them all) as an update (PUT) to SysImageCollection(guid'guid')/PreviewData.
Everything runs correct but I don't see any picture change in the contacts.
I use the guid of the contact in both steps.
Maybe I have to use a fresh guid and link that guid to the ContactCollection afterwards?
Does anyone have an idea what the json is to update the the profile picture for a contact?
Thanks in advance,
Kristof Leroux - Laranea
Like
It's hard to say how to create the integration on PHP. I created the functionality on c# and caught the requests with fiddler.
using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Net; using System.Xml; using System.Xml.Linq; namespace TransferImageViaOData { class Program { // String of address bpm’online OData servise. private const string serverUri = "https://023148-crm-bundle.bpmonline.com/0/ServiceModel/EntityDataService.svc/"; private const string authServiceUtri = "https://023148-crm-bundle.bpmonline.com/ServiceModel/AuthService.svc/Login"; // Links to XML name spaces. private static readonly XNamespace ds = "http://schemas.microsoft.com/ado/2007/08/dataservices"; private static readonly XNamespace dsmd = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"; private static readonly XNamespace atom = "http://www.w3.org/2005/Atom"; private static readonly Guid ContactId = new Guid("410006e1-ca4e-4502-a9ec-e54d922d2c00"); static void Main(string[] args) { var file = ReadFile("z:/2SupportLine/features.png"); var id = CreateBpmEntityByOdataHttpExample(); TransferImage(id, "Data", file); UpdateContactAvatar(id); } public static Guid CreateBpmEntityByOdataHttpExample() { Guid id = Guid.NewGuid(); // Creating a xml message containing data on the created object. var content = new XElement(dsmd + "properties", new XElement(ds + "Id", id.ToString()), new XElement(ds + "HasRef", 0), new XElement(ds + "MimeType", "image/png"), new XElement(ds + "Name", "test1.png") ); var entry = new XElement(atom + "entry", new XElement(atom + "content", new XAttribute("type", "application/xml"), content)); Console.WriteLine(entry.ToString()); // Creating a request to the service which will add a new object to the contacts collection. var request = (HttpWebRequest)HttpWebRequest.Create(serverUri + "SysImageCollection/"); request.Credentials = new NetworkCredential("Supervisor", "Supervisor"); request.Method = "POST"; request.Accept = "application/atom+xml"; request.ContentType = "application/atom+xml;type=entry"; // Recording the xml message to the request stream. using (var writer = XmlWriter.Create(request.GetRequestStream())) { entry.WriteTo(writer); } // Receiving a response from the service regarding the operation implementation result. using (WebResponse response = request.GetResponse()) { if (((HttpWebResponse)response).StatusCode == HttpStatusCode.Created) { // Processing the operation implementation result. } } return id; } public static void TransferImage(Guid fileRecordId, string columnName, byte[] file) { // Creating a request to the service which will add a new object to the contacts collection. var request = (HttpWebRequest)HttpWebRequest.Create(serverUri + "SysImageCollection(guid'" + fileRecordId.ToString() + "')/" + columnName); request.Credentials = new NetworkCredential("Supervisor", "Supervisor"); request.Method = "PUT"; request.Accept = "application/octet-stream,application/json;odata=verbose"; request.ContentType = "multipart/form-data;boundary=+++++"; // Recording the xml message to the request stream. using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(file, 0, file.Length); } // Receiving a response from the service regarding the operation implementation result. using (WebResponse response = request.GetResponse()) { if (((HttpWebResponse)response).StatusCode == HttpStatusCode.Created) { // Processing the operation implementation result. } } } public static void UpdateContactAvatar(Guid fileRecordId) { var content = new XElement(dsmd + "properties", new XElement(ds + "PhotoId", fileRecordId) ); var entry = new XElement(atom + "entry", new XElement(atom + "content", new XAttribute("type", "application/xml"), content) ); var request = (HttpWebRequest)HttpWebRequest.Create(serverUri + "ContactCollection(guid'" + ContactId + "')"); request.Credentials = new NetworkCredential("Supervisor", "Supervisor"); // or request.Method = "MERGE"; request.Method = "PUT"; request.Accept = "application/atom+xml"; request.ContentType = "application/atom+xml;type=entry"; // Recording the xml message to the request stream. using (var writer = XmlWriter.Create(request.GetRequestStream())) { entry.WriteTo(writer); } // Receiving a response from the service regarding the operation implementation result. using (WebResponse response = request.GetResponse()) { // Processing the operation implementation result. } } public static byte[] ReadFile(string filePath) { byte[] imageArray = System.IO.File.ReadAllBytes(filePath); return imageArray; } } }
Please use the code below:
<?php
/*Please change this to you product name*/
define("baseUri", "https://023665-crm-bundle.bpmonline.com");
define("serverUri", baseUri . "/0/ServiceModel/EntityDataService.svc");
/*Please change this to you account setting*/
define("user", "Dmitro");
define("password", "123456789");
/*Please change this user_id to new user_id value for the user whose avatar needs to be changed*/
$user_id = 'c4ed336c-3e9b-40fe-8b82-5632476472b4';
/*Please change this file name*/
$file_name = 'test_img.png';
$file_id = CreateBpmEntityFile($file_name);
TransferImage($file_id, $file_name);
UpdateContactAvatar($user_id, $file_id);
function CreateBpmEntityFile($file_name) {
    $headers = [
      'Accept: application/atom+xml',
      'Content-Type: application/atom+xml;type=entry',
      "Authorization: Basic " . base64_encode(user . ':' . password),
      'Expect: 100-continue',
    ];
$uid = GetUid();
    $postData = <<<XML
<?xml version="1.0" encoding="utf-8"?><entry xmlns="http://www.w3.org/2005/Atom"><content type="application/xml"><properties xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><Id xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">$uid</Id><HasRef xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">0</HasRef><MimeType xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">image/png</MimeType><Name xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">$file_name</Name></properties></content></entry>
XML;
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, serverUri . "/SysImageCollection/");
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    curl_exec($ch);
    curl_close($ch);
    return $uid;
}
function TransferImage($id, $file_name) {
    $fh_res = fopen($file_name, 'r');
    $xml_data = fread($fh_res, filesize($file_name));
    $headers = [
      "Accept: application/octet-stream,application/json;odata=verbose",
      "Content-type: multipart/form-data;boundary=+++++",
      "Authorization: Basic " . base64_encode(user . ':' . password),
      "Expect: 100-continue",
    ];
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, serverUri . "/SysImageCollection(guid'$id')/Data");
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($ch, CURLOPT_BINARYTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_POST, TRUE);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_data);
    curl_exec($ch);
    fclose($fh_res);
}
function UpdateContactAvatar($user_id, $file_id) {
    $headers = [
      'Accept: application/atom+xml',
      'Content-Type: application/atom+xml;type=entry',
      "Authorization: Basic " . base64_encode(user . ':' . password),
    ];
    $postData = <<<XML
<?xml version="1.0" encoding="utf-8"?><entry xmlns="http://www.w3.org/2005/Atom"><content type="application/xml"><properties xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><PhotoId xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">$file_id</PhotoId></properties></content></entry> 
XML;
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, serverUri . "/ContactCollection(guid'$user_id')");
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($ch, CURLOPT_BINARYTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_POST, TRUE);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
    curl_exec($ch);
    curl_close($ch);
}
/**
 * Generate uniq id
 *
 * @return string
 */
function GetUid() {
    $uid = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
      mt_rand(0, 0xffff), mt_rand(0, 0xffff),
      mt_rand(0, 0xffff),
      mt_rand(0, 0x0fff) | 0x4000,
      mt_rand(0, 0x3fff) | 0x8000,
      mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff));
    return $uid;
}
Mark Bailey,
Thanks Mark for your solution. It is working but I need to use it as a service and my implementation goes like::
// Endpoint
        [OperationContract]
        [WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
        ResponseFormat = WebMessageFormat.Json)]
        public string UploadContactPicture(Data data)
        {
            CifNoVar = data.CIFNo;
            ContactId = Guid.Parse(GetContactIdByCIF(data.CIFNo));
            var file = ReadFile(data.Image);
            var id = CreateBpmEntityByOdataHttpExample();
            TransferImage(id, "Data", file);
            UpdateContactAvatar(id);
            return ContactId.ToString();
        }
where Data is::
[DataContract]
    public class Data
    {
        [DataMember]
        public string CIFNo { get; set; }
        [DataMember]
        public string Image { get; set; }
    }
The UploadContactPicture is working well to upload a contact picture when my implementation is::
[OperationContract]
        [WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
        ResponseFormat = WebMessageFormat.Json)]
        public string UploadContactPicture(string CIFNo)
        {
            CifNoVar = CIFNo;
            ContactId = Guid.Parse(GetContactIdByCIF(CIFNo));
            var file = ReadFile("E:/SBL_QA/Terrasoft.WebApp/conf/content/img/OBSWConsultationPanelSchema-DefaultContactPhoto.jpg");
            var id = CreateBpmEntityByOdataHttpExample();
            TransferImage(id, "Data", file);
            UpdateContactAvatar(id);
            return ContactId.ToString();
        }
How can I use a JSON object(Model object) as a parameter to the UploadContactPicture method to successfully upload a picture as shown in the example above.
Dear,
In order to resolve the issue please use the article by the link below:
Best regards,
Norton
Norton Lingard,
Hi Norton, thanks for your reply. I had tried it, but it didn't work. It says::
403 - Forbidden: Access is denied. You do not have permission to view this directory or page using the credentials that you supplied.
This is my full implementation::
namespace Terrasoft.Configuration.SBLCustomNamespace
{
    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 Terrasoft.Core.DB;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Xml;
    using System.Xml.Linq;
    using System.Web.Hosting;
    using System.Runtime.Serialization;
    
    [DataContract]
    public class Data
    {
        [DataMember]
        public string CIFNo { get; set; }
        [DataMember]
        public string Image { get; set; }
    }
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class SBLContactPictureUploaderService: BaseService
    {
        // Link to the UserConnection instance required to access the database.
        private SystemUserConnection _systemUserConnection;
        private SystemUserConnection SystemUserConnection {
            get {
                return _systemUserConnection ?? (_systemUserConnection = (SystemUserConnection)AppConnection.SystemUserConnection);
            }
        }
        
        // String of address bpm’online OData service.
        private const string serverUri = "https://qacrm.siddharthabank.com/0/ServiceModel/EntityDataService.svc/";
        private const string authServiceUtri = "https://qacrm.siddharthabank.com/ServiceModel/AuthService.svc/Login";
 
        // Links to XML name spaces.
        private readonly XNamespace ds = "http://schemas.microsoft.com/ado/2007/08/dataservices";
        private readonly XNamespace dsmd = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
        private readonly XNamespace atom = "http://www.w3.org/2005/Atom";
 
        private Guid ContactId = Guid.NewGuid();
        
        private string CifNoVar = string.Empty;
 
         // A method that returns the contact's ID by its name.
        [OperationContract]
        [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare,
        ResponseFormat = WebMessageFormat.Json)]
        public string UploadContactPicture(Data data)
        {
            CifNoVar = data.CIFNo;
            ContactId = Guid.Parse(GetContactIdByCIF(data.CIFNo));
            var file = ReadFile(data.Image);
            var id = CreateBpmEntityByOdataHttpExample();
            TransferImage(id, "Data", file);
            UpdateContactAvatar(id);
            return ContactId.ToString();
        }
        
        public Guid CreateBpmEntityByOdataHttpExample()
        {
            Guid id = Guid.NewGuid();
            // Creating a xml message containing data on the created object.
            var content = new XElement(dsmd + "properties",
                          new XElement(ds + "Id", id.ToString()),
                          new XElement(ds + "HasRef", 0),
                          new XElement(ds + "MimeType", "image/jpg"),
                          new XElement(ds + "Name", CifNoVar.ToString().Trim()+".jpg")
                          );
            var entry = new XElement(atom + "entry",
                        new XElement(atom + "content",
                        new XAttribute("type", "application/xml"), content));
            Console.WriteLine(entry.ToString());
            // Creating a request to the service which will add a new object to the contacts collection.
            var request = (HttpWebRequest)HttpWebRequest.Create(serverUri + "SysImageCollection/");
            request.Credentials = new NetworkCredential("Supervisor", "Supervis0r@1234%");
            request.Method = "POST";
            request.Accept = "application/atom+xml";
            request.ContentType = "application/atom+xml;type=entry";
            // Recording the xml message to the request stream.
            using (var writer = XmlWriter.Create(request.GetRequestStream()))
            {
                entry.WriteTo(writer);
            }
            // Receiving a response from the service regarding the operation implementation result.
            using (WebResponse response = request.GetResponse())
            {
                if (((HttpWebResponse)response).StatusCode == HttpStatusCode.Created)
                {
                    // Processing the operation implementation result.
                }
            }
            return id;
        }
 
        public void TransferImage(Guid fileRecordId, string columnName, byte[] file)
        {
            // Creating a request to the service which will add a new object to the contacts collection.
            var request = (HttpWebRequest)HttpWebRequest.Create(serverUri + "SysImageCollection(guid'" + fileRecordId.ToString() + "')/" + columnName);
            request.Credentials = new NetworkCredential("Supervisor", "Supervis0r@1234%");
            request.Method = "PUT";
            request.Accept = "application/octet-stream,application/json;odata=verbose";
            request.ContentType = "multipart/form-data;boundary=+++++";
            // Recording the xml message to the request stream.
            using (Stream requestStream = request.GetRequestStream())
            {
                requestStream.Write(file, 0, file.Length);
            }
            // Receiving a response from the service regarding the operation implementation result.
            using (WebResponse response = request.GetResponse())
            {
                if (((HttpWebResponse)response).StatusCode == HttpStatusCode.Created)
                {
                    // Processing the operation implementation result.
                }
            }
        }
 
        public void UpdateContactAvatar(Guid fileRecordId)
        {
            var content = new XElement(dsmd + "properties",
                    new XElement(ds + "PhotoId", fileRecordId)
            );
            var entry = new XElement(atom + "entry",
                    new XElement(atom + "content",
                            new XAttribute("type", "application/xml"),
                            content)
                    );
            var request = (HttpWebRequest)HttpWebRequest.Create(serverUri
                    + "ContactCollection(guid'" + ContactId + "')");
            request.Credentials = new NetworkCredential("Supervisor", "Supervis0r@1234%");
            // or request.Method = "MERGE";
            request.Method = "PUT";
            request.Accept = "application/atom+xml";
            request.ContentType = "application/atom+xml;type=entry";
            // Recording the xml message to the request stream.
            using (var writer = XmlWriter.Create(request.GetRequestStream()))
            {
                entry.WriteTo(writer);
            }
            // Receiving a response from the service regarding the operation implementation result.
            using (WebResponse response = request.GetResponse())
            {
                // Processing the operation implementation result.
            }
        }
 
        public static byte[] ReadFile(string filePath)
        {
            byte[] imageArray = System.IO.File.ReadAllBytes(filePath);
            return imageArray;
        }
        
        // A method that returns the contact's ID by its name.
        [OperationContract]
        [WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
        ResponseFormat = WebMessageFormat.Json)]
        public string GetContactIdByName(string Name){
            // The default result.
            var result = "";
            // An EntitySchemaQuery instance that accesses the Contact table of the database.
            var esq = new EntitySchemaQuery(SystemUserConnection.EntitySchemaManager, "Contact");
            // Adding columns to the query.
            var colId = esq.AddColumn("Id");
            var colName = esq.AddColumn("Name");
            // Filter the query data.
            var esqFilter = esq.CreateFilterWithParameters(FilterComparisonType.Equal, "Name", Name);
            esq.Filters.Add(esqFilter);
            // Get the result of the query.
            var entities = esq.GetEntityCollection(SystemUserConnection);
            // If the data is received.
            if (entities.Count > 0)
            {
                // Return the value of the "Id" column of the first record of the query result.
                result = entities[0].GetColumnValue(colId.Name).ToString();
                // You can also use this option:
                // result = entities [0]. GetTypedColumnValue <string> (colId.Name);
            }
            // Return the result.
            return result;
        }
        
        public string GetContactIdByCIF(string CIFNo){
            // The default result.
            var result = "";
            // An EntitySchemaQuery instance that accesses the Contact table of the database.
            var esq = new EntitySchemaQuery(SystemUserConnection.EntitySchemaManager, "Contact");
            // Adding columns to the query.
            var colId = esq.AddColumn("Id");
            var colName = esq.AddColumn("SBLCIF");
            // Filter the query data.
            var esqFilter = esq.CreateFilterWithParameters(FilterComparisonType.Equal, "SBLCIF", CIFNo);
            esq.Filters.Add(esqFilter);
            // Get the result of the query.
            var entities = esq.GetEntityCollection(SystemUserConnection);
            // If the data is received.
            if (entities.Count > 0)
            {
                // Return the value of the "Id" column of the first record of the query result.
                result = entities[0].GetColumnValue(colId.Name).ToString();
                // You can also use this option:
                // result = entities [0]. GetTypedColumnValue <string> (colId.Name);
            }
            // Return the result.
            return result;
        }
        
        [OperationContract]
        [WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
        ResponseFormat = WebMessageFormat.Json)]
        public string InsertContact(string contactName)
        {
            contactName = contactName ?? "Unknown contact";
            var ins = new Insert(UserConnection)
                .Into("Contact")
                .Set("Name", Column.Const(contactName));
            var affectedRows = ins.Execute();
            var result = $"Inserted new contact with name '{contactName}'. {affectedRows} rows affected";
            return result;
        }
    }
}
Dear,
In order to resolve the issue please use the article by the link below:
https://community.creatio.com/questions/403-forbidden-when-using-post-custom-service
Best regards,
Norton
 
  