Showing posts with label file. Show all posts
Showing posts with label file. Show all posts

Thursday, October 17, 2024

Uploading files to SharePoint Online

Here are the steps to upload files to SharePoint Online using PeopleSoft's services/service operations.

I am running PeopleTools 8.61.x and there are some properties that are discussed below that are only available in the latest tools release. 

At a high level there are three steps

1. Generate Access Token

2. Using the access token generate Form Digest

3. Finally using both the access token and form digest upload file to SPO.

Service and Service Operation build

1. Created a Document Template (N_SPO_URI_TEMPLATE) with the following primitives defined as text.

TenantID, TenantName, SiteName, SPOFolder and FileName

2. Defined two non-rowset based messages - N_SPO_REQUEST and N_SPO_RESPONSE

3. Created a consumer REST service called as N_SPO.

4. Created three service operations all with REST method as POST - 

N_SPO_ACCESSTOKEN_POST, N_SPO_FORMDIGEST_POST and N_SPO_UPLOADFILES_POST

For the service operation N_SPO_ACCESSTOKEN_POST the REST base URL is 

https://accounts.accesscontrol.windows.net/ and template is {TenantID}/tokens/OAuth/2

For the service operation N_SPO_FORMDIGEST_POST the REST base URL is https:// and 

template is {TenantName}.sharepoint.com/sites/{SiteName}/_api/ContextInfo as we cannot provide any variables in the base URL.

Finally for the N_SPO_UPLOADFILES_POST service operation, the REST base URL is https:// and template is {TenantName}.sharepoint.com/sites/{SiteName}/_api/web/GetFolderByServerRelativeURL('/sites/{SiteName}/{SPOFolder}/')/Files/add(url='{FileName}',overwrite=true)

All other settings are default settings.

5. Updated the integrationGateway.properties file as follows - (this parameter may be available only in the latest tools release)

ig.UseDomainName.ExternalOperationNames=N_SPO_FORMDIGEST.v1,N_SPO_UPLOADFILES.v1

Had to provide external operational service name for these two. The first one related to access token generation worked without having to define it here. 

6. For the SPO site to which I want to upload the file, I need a Client ID and Secret, which is kind of like the user ID/password to make the connection. SharePoint admin can generate this. Value for &ApplicationID, &TenantID also provided by SharePoint admin. Value for variables like &TenantName, &SiteName, &SPOFolder derived by parsing the SPO URL to which I had to upload the file. &attachFileName is derived from the complete file path of the file to be uploaded.  

7. Now comes the peoplecode part to invoke these service operations. 

/* step 1 */
/* intialize service operation and update URL variables */
&reqMsg = CreateMessage(Operation.N_SPO_ACCESSTOKEN_POST);
&Doc_Tmpl = &reqMsg.GetURIDocument();
&COM_Tmpl = &Doc_Tmpl.DocumentElement;
&reqMsg.URIResourceIndex = 1;
&COM_Tmpl.GetPropertyByName("TenantID").Value = &TenantID;

/* this is how form-data can be provided */
&reqMsg.SegmentContentType = "application/x-www-form-urlencoded";
&bRet = &reqMsg.SetContentString("grant_type=client_credentials&client_id=" | EncodeURLForQueryString(&ClientID | "@" | &TenantID) | "&client_secret=" | EncodeURLForQueryString(&ClientSecret) | "&resource=" | EncodeURLForQueryString(&ApplicationID | "/" | &TenantName | ".sharepoint.com@" | &TenantID));

/* following HTTP property may only work in latest tools release */
&bRet = &reqMsg.IBInfo.LoadRESTHeaders();
&bRet = &reqMsg.IBInfo.IBConnectorInfo.AddConnectorProperties("Disable_URLEncodingBody", "True", %HttpProperty);

/* submit request and the parse json response */
&respMsg = %IntBroker.SyncRequest(&reqMsg);
&sResp = &respMsg.GenXMLString();
&AccessToken will have the access token received in the response. 

/* step 2 */
/* intialize service operation and update URL variables */
&reqMsg = CreateMessage(Operation.N_SPO_FORMDIGEST_POST);
&Doc_Tmpl = &reqMsg.GetURIDocument();
&COM_Tmpl = &Doc_Tmpl.DocumentElement;
&reqMsg.URIResourceIndex = 1;
&COM_Tmpl.GetPropertyByName("TenantName").Value = &TenantName;
&COM_Tmpl.GetPropertyByName("SiteName").Value = &SiteName;

/* add properties to request header, &AccessToken is from step 1 */
&bRet = &reqMsg.IBInfo.LoadRESTHeaders();
&bRet = &reqMsg.IBInfo.IBConnectorInfo.AddConnectorProperties("Authorization", &AccessToken, %Header);
&bRet = &reqMsg.IBInfo.IBConnectorInfo.AddConnectorProperties("Accept", "application/json;odata=nometadata", %Header);

/* submit request and the parse json response */
&respMsg = %IntBroker.SyncRequest(&reqMsg);
&sResp = &respMsg.GenXMLString();
&FormDigest will be populated form the response.

/* step 3 */
/* intialize service operation and update URL variables */
&reqMsg = CreateMessage(Operation.N_SPO_UPLOADFILES_POST);
&Doc_Tmpl = &reqMsg.GetURIDocument();
&COM_Tmpl = &Doc_Tmpl.DocumentElement;
&reqMsg.URIResourceIndex = 1;
&COM_Tmpl.GetPropertyByName("TenantName").Value = &TenantName;
&COM_Tmpl.GetPropertyByName("SiteName").Value = &SiteName;
/* if SPO folder path has space in it then it has to be encoded like &SPOFolder = EncodeURL("Shared Documents/General/SPO Test"); */
&COM_Tmpl.GetPropertyByName("SPOFolder").Value = &SPOFolder;
&COM_Tmpl.GetPropertyByName("FileName").Value = &attachFileName;

/* read the file to attach and GetBase64StringFromBinary */
&MTOMFile = GetFile("filename.xlsx", "R", %FilePath_Absolute);
If &MTOMFile.IsOpen Then
   &theBase64encodedString = &MTOMFile.GetBase64StringFromBinary();
   &MTOMFile.Close();
End-If;

/* add the bas464string to request message */
If (&reqMsg.SetContentString(&theBase64encodedString)) Then
   &reqMsg.SegmentContentType = "binary";
   &reqMsg.SegmentContentTransfer = %ContentTransfer_Binary;
End-If;

/* add properties to request header, last property is a HTTP property */
&bRet = &reqMsg.IBInfo.LoadRESTHeaders();
&bRet = &reqMsg.IBInfo.IBConnectorInfo.AddConnectorProperties("X-Request-Digest", &FormDigest, %Header);
&bRet = &reqMsg.IBInfo.IBConnectorInfo.AddConnectorProperties("Authorization", &AccessToken, %Header);
&bRet = &reqMsg.IBInfo.IBConnectorInfo.AddConnectorProperties("Accept", "application/json;odata=nometadata", %Header);
&bRet = &reqMsg.IBInfo.IBConnectorInfo.AddConnectorProperties("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", %Header);
&bRet = &reqMsg.IBInfo.IBConnectorInfo.AddConnectorProperties("Base64toBinary", "Y", %HttpProperty);

/* submit request and the parse json response */
&respMsg = %IntBroker.SyncRequest(&reqMsg);
&sResp = &respMsg.GenXMLString();

Parse the response or check response status &respMsg.HTTPResponseCode
or &respMsg.ResponseStatus to complete the processing.

Hope this helps.

Thursday, April 19, 2018

SQR: FindFiles

Via peoplecode its very easy to read a directory and fetch filenames - leveraging delivered function "FindFiles". Now try doing the same in SQR. Not trivial at all. 

Here is what I had to do. I am running PT 8.55.x but its pretty much the same in any recent PT versions.
I essentially have to run a dir command at the Windows level get the filenames based on the wildcard and write the filenames to a file. Then read the file for the filenames. Once done, I can delete the temp file which has the list of filenames. if the dir cmd does not return anything for my wildcard search then the temp file will be empty.
The other important thing here is the WAIT parameter for the call system command. If that is not provided then the reading of the temp file does not work, as it takes the system some time to write the contents to the temp file. 

let $comspec = getenv('COMSPEC')
let $TempFile = 'C:\temp\temp_file.txt'
let $FindFiles = $comspec || ' /c dir /b \\my_network_path\share\some_directory\*.pdf > ' ||  $TempFile
call system using $FindFiles #call-status WAIT

open $TempFile as 10 for-reading record=50 #filestat
while 1 
  read 10 into $file-name:50
if $file-name != '' or #end-file
break
end-if
end-while

close 10

! delete text file
let $delCmd = $comspec || ' /c del /F /Q ' || $TempFile 
call system using $delCmd  #call-status WAIT

Way longer than a simple FindFiles command via peoplecode, but this does the trick.