Box for Salesforce Developers Toolkit Authorization Issue - apex

Is anyone out there using the new Box for Salesforce Developers Toolkit? The documentation is pretty sketchy on how Auth works and I'm getting an error returned that the method is, "Unable to use default credentials to make a callout to box." Any ideas?
public void onAfterInsert(List<Claimant__c> newClaimants, Map<Id, Claimant__c> newClmtMap) {
box.Toolkit boxToolkit = new box.Toolkit();
for(Claimant__c aClaimant : newClaimants){
String claimantFolderId = boxToolkit.createFolderforRecordId(aClaimant.Id, aClaimant.Last_Name__c + ', ' + aClaimant.First_Name__c, true);
boxToolkit.commitChanges();
//debug code - mf
string clmfld = [SELECT folderId__c from Claimant__c where id =: aclaimant.id].folderId__c;
system.debug('-->CFolderID: ' + clmfld);
}
}//end onAfterInsert

If you use this method in a trigger context, you should defined it with #future (callout=true). An Apex trigger can only execute a callout from a asynchronous method.

Related

Runnable.Run / StartCoroutine calles to Watson services from Unity

In my ExampleStreaming.cs script, once the user utterance is recognized as final, I send it to both the Watson Assistant service and the Tone Analyzer. Because I am keeping the scripts for each service separate as they are, I have to make calls within each script to access the other service. You can see the call I make to the Tone Analyzer below (the .SendToneAnalysis method):
private void OnRecognize(SpeechRecognitionEvent result, Dictionary<string, object> customData)
{
blah blah blah . . .
/// Only send the recognized speech utterance to the
/// Assistant once we know the user has stopped talking.
if (res.final)
{
string _conversationString = alt.transcript;
Runnable.Run( StopRecording(1f) ); // Stop the microphone from listening.
/// Message.
Dictionary<string, object> input = new Dictionary<string, object>
{
["text"] = _conversationString
};
MessageRequest messageRequest = new MessageRequest()
{
Input = input,
Context = _Context
};
_exampleAssistantV1_script.SendMessageAssistant(messageRequest);
_exampleToneAnalyzer.SendToneAnalysis(_conversationString);
. . .
In my ExampleToneAnalyzer.cs script, I make a simple call to the event-handling methods that are meant to contact the service and also handle success & failure:
public void SendToneAnalysis(string conversationString)
{
_service.GetToneAnalyze(OnGetToneAnalyze, OnFail, conversationString);
}
These calls are typically made using StartCoroutines, particularly in the Watson Unity SDK that there is a specialized Runnable.Run which is essentially a helper class for running co-routines without having to inherit from MonoBehavior.
My question is whether my simple method call to the service might be problematic in certain situations or perhaps just wrong or bad programming, or whether it is perfectly OK to go for that method instead of something like the following:
public void SendToneAnalysis(string conversationString)
{
Runnable.Run( SendAssistantToneAnalysis(conversationString) );
}
private IEnumerator SendAssistantToneAnalysis(string conversationString)
{
if ( !_service.GetToneAnalyze(OnGetToneAnalyze, OnFail, conversationString) )
{
Log.Debug("ExampleToneAnalyzer.SendAssistantToneAnalysis()", "Failed to analyze!");
}
while (!_UserUtteranceToneTested)
yield return null;
}
You don't need to make any of the service calls from within a coroutine. Only authentication using iamApikey should be done using a coroutine
IEnumerator TokenExample()
{
// Create IAM token options and supply the apikey. IamUrl is the URL used to get the
// authorization token using the IamApiKey. It defaults to https://iam.bluemix.net/identity/token
TokenOptions iamTokenOptions = new TokenOptions()
{
IamApiKey = "<iam-api-key>",
IamUrl = "<iam-url>"
};
// Create credentials using the IAM token options
_credentials = new Credentials(iamTokenOptions, "<service-url>");
while (!_credentials.HasIamTokenData())
yield return null;
_assistant = new Assistant(_credentials);
_assistant.VersionDate = "2018-02-16";
_assistant.ListWorkspaces(OnListWorkspaces, OnFail);
}
The examples are only meant to show how to invoke the service call. The only reason the code is invoked from a coroutine is so we can wait for the response of one service call before running another service call (i.e. so we don't try to update or delete a workspace before the workspace is created).
It's no problem.
Runnable.Run() eventually calls StartCoroutine() as the follow.
public Routine(IEnumerator a_enumerator)
{
_enumerator = a_enumerator;
Runnable.Instance.StartCoroutine(this);
Stop = false;
ID = Runnable.Instance._nextRoutineId++;
Runnable.Instance._routines[ID] = this;
#if ENABLE_RUNNABLE_DEBUGGING
Log.Debug("Runnable.Routine()", "Coroutine {0} started.", ID );
#endif
}
Please refer to https://github.com/watson-developer-cloud/unity-sdk/blob/master/Scripts/Utilities/Runnable.cs
And the coroutine can be called from any gameobject, if it is active.

Callback function issues in FB.API for Unity

I am using Unity 5.5.2f1 pro and facebook's SDK v 7.9.4
I have a script which after login (managed in a previous scene) sends an API request to FB asking for friends, name and email and sends that info as a POST to a php website.
code:
[Serializable]
public struct FBData {
public string first_name;
public string email;
public string friends;
public string id;}
public class UserManagement : MonoBehaviour {
string urlSaveUserData="some php website";
public Text testTxt;
FBData parsedData;
// Use this for initialization
void Start () {
//Check if it's the first time the user is opening the app.
if (UserInfo.FIRST_TIME) {
//update text (only used for testing, should be removed in production.)
testTxt.text = "Your user id is: " + UserInfo.ID;
//Perform FB.API call to get User Data.
getUserData ();
//Save in SQL table. (won't get here if line in getUserData() is active)
StartCoroutine ("saveUserData");
} else {
//do something else.
}
note: Since this is meant for iOS I have to test it on a device so I'm using text in the screen to display info (think of it as a badly implemented print statement).
The problem: In my callback function for FB.API I write in the text Gameobject (aka testTxt) the parsed information from the response which is saved in the Custom UserInfo clss. It display's correctly but the code gets stuck there. It doesn't continue to the next function. HOWEVER, if I delete/comment that line and don't display anything in the text field. The codes does continue to the POST function BUT the information from the API call is not passed, i.e my custom class is empty (leading me to believe the callback function is not called at all).
public void getUserData(){
string query = "me?fields=first_name,email,friends";
FB.API (query, HttpMethod.GET, Apicallback, new Dictionary<string, string> ());
}
private void Apicallback(IGraphResult result){
//Parse Graph response into a specific class created for this result.
parsedData = JsonUtility.FromJson<FBData>(result.RawResult);
//Pass each field into UserInfo class.
UserInfo.EMAIL = parsedData.email;
UserInfo.FRIENDS = parsedData.friends;
UserInfo.NAME = parsedData.first_name;
UserInfo.FACEBOOKID = parsedData.id;
/*problem area, if I comment line below, then previous information is apparently not stored. If left as is then testTxt displays correct information but code gets stuck there. */
testTxt.text = "This is the info from USerInfoInside the APICallback: " + UserInfo.EMAIL + UserInfo.FRIENDS + UserInfo.FACEBOOKID;
}
The function below is to send info to php website, is there for illustrative purposes:
code:
public IEnumerator saveUserData() {
//get user info (this information is EMPTY if line in getUserData() is commented.
parsedData.id = UserInfo.FACEBOOKID;
parsedData.friends = UserInfo.FRIENDS;
parsedData.first_name = UserInfo.NAME;
parsedData.email = UserInfo.EMAIL;
//translate data into json
string JsonBodyData = JsonUtility.ToJson (parsedData);
//Custom web request (POST method doesnt seem to work very well, documentation example sends empty form)
var w = new UnityWebRequest(urlSaveUserData, "POST");
byte[] bodyRaw = new System.Text.UTF8Encoding().GetBytes(JsonBodyData);
w.uploadHandler = (UploadHandler) new UploadHandlerRaw(bodyRaw);
w.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer();
w.SetRequestHeader("Content-Type", "application/json");
yield return w.Send();
//work with received data...}
Im stuck here any help is appreciated. Thanks!
Be sure to use EscapeURL when using strings directly for JSON or HTTP POST and GET methods. The lack of this treatment tends to screw things over, particulary in iOS platforms.
From what I can see, this code
string query = "me?fields=first_name,email,friends";
should instead be escaped as
string query = WWW.EscapeURL("me?fields=first_name,email,friends");
so characters like "?" won't get encoded as an URL symbol.
I'm assuming you don't need to do that for your illustrative example, because UnityWebRequest already escapes your POST request strings internally, but I can't fully confirm that.

create token in unity to send post request to laravel controller

I wanna send a post request from a unity game to a laravel 5.4 controller.. in html form, we use {{csrf_field}} and it handles creating token. but how can I do it in unity?
I came across this thread whilst trying to acheive what it set out to do - and I got it working so I am sharing this:
It is a combination of this tutorial on YouTube: How to Use UnityWebRequest - Replacement for WWW Class - Unity Tutorial and this answer on a similar question: UnityWebRequest POST to PHP not work
The technology I am using:
Laravel Framework 7.15.0 (PHP)
Unity: 2019.3.11f1 (script is C#)
Now I am just sending basic forms not images etc - so I haven't tried anything complex but this sends a get to one URL on Laravel which returns the CSRF token.
This is then added as an additional field to the post request.
I am clicking the 2 buttons pretty quickly - I would suggest (and will implement this myself later) that you don't ask for the token until your ready to submit the form - to avoid it expiring if your form is quite long etc.
The C# Script (Unity)
Both the functions are set as ON Click() on the buttons in a simple UI Canvas in Unity.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
public class BasicWebCall : MonoBehaviour
{
public Text messageText;
public InputField scoreToSend;
private string csrf_token;
readonly string getURL = "http://mazegames.test/leaderboard/1";
readonly string postURL = "http://mazegames.test/register/1";
private void Start()
{
messageText.text = "Press buttons to interact with web server";
}
public void OnButtonGetScore()
{
messageText.text = "Getting Token";
StartCoroutine(SimpleGetRequest());
}
IEnumerator SimpleGetRequest()
{
UnityWebRequest www = UnityWebRequest.Get(getURL);
yield return www.SendWebRequest();
if(www.isNetworkError || www.isHttpError)
{
Debug.LogError(www.error);
}
else
{
messageText.text = "Token Received: " + www.downloadHandler.text;
csrf_token = www.downloadHandler.text;
}
}
public void OnButtonSendScore()
{
if (scoreToSend.text == string.Empty)
{
messageText.text = "Error: No high score to send.\nEnter a value in the input field.";
}
else
{
messageText.text = "Sending Post Request";
StartCoroutine(SimplePostRequest(scoreToSend.text));
}
}
IEnumerator SimplePostRequest(string curScore)
{
Dictionary<string, string> wwwForm = new Dictionary<string, string>();
wwwForm.Add("_token", csrf_token);
UnityWebRequest www = UnityWebRequest.Post(postURL, wwwForm);
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.LogError(www.error);
}
else
{
messageText.text = www.downloadHandler.text;
}
}
}
Laravel routes/web.php
Obviously you need to configure your end points to receive your data, validate and store it if necessary. In this example its just validating the token as part of the post request.
Route::post('register/{game_id}', function($game_id) {
return "Game On!";
});
Route::get('leaderboard/{game_id}', function($game_id) {
return csrf_token();
});
And that is pretty much it - hope this helps someone else.
#EDIT# - Request Token on Submission
To only get the token when your submitting the form, literally all you have to do is put this line:
StartCoroutine(SimpleGetRequest());
above the line:
StartCoroutine(SimplePostRequest(scoreToSend.text));
so that is looks like this:
StartCoroutine(SimpleGetRequest());
StartCoroutine(SimplePostRequest(scoreToSend.text));
Obviously you could then remove the function SimpleGetRequest altogether.
Laravel will generate a token each time a page is generated. The token has a lifetime and after that lifetime it cannot be used anymore (that's the whole point).
You need to get a valid token from Laravel pass it to Unity3D and then when from Unity create a WWWForm and pass it back.
How to do this it depends on the platform that Unity3D is deployed to.
If you are using WebPlayer or WebGL then you can get your hand on the Unity3D objected embedded in the browser and use SendMessage. WebGL link here.
If the game is deployed to another platform it probably makes sense to expose and API on the Laravel side and use that endpoint instead of doing a POST request.
You can use WWWForm to send in POST and call it from a coroutine:
// this will send it at start
// but you can just call SendToController in another function
string laravel_url = "http://somedomain.com/whatever";
IEnumerator Start () {
yield return StartCoroutine(SendToController());
}
IEnumerator SendToController()
{
WWWForm form = new WWWForm();
form.AddField( "csrf_field", "replace this with what you want!!!!" );
WWW download = new WWW( laravel_url, form );
yield return download;
if(!string.IsNullOrEmpty(download.error)) {
print( "Error downloading: " + download.error );
} else {
// if succesful, do what you want
Debug.Log(download.text);
}
}
"Coroutine" is your friend. It will make sending forms a lot easier. You might want to read about it in here:
https://docs.unity3d.com/ScriptReference/MonoBehaviour.StartCoroutine.html

Changing user folder collaborating type in box using Salesforce Toolbox

I'm trying to change Box folder collaboration type for user from salesforce Apex trigger. The first thoughts were to use box.Toolkit but it looks like this class does not have updateCollaboration or changeCollaboration method, only create. I guess my only option is to use Box's Rest API. Is there any way I can get service account token in Apex so I can use it in a callout?
I have created a special "Tokens" object in Salesforce with two fields: access token and refresh token. I then have a batch job that runs to update the access token every 55 minutes such that they never expired.
Here is a code snippet in APEX using the Tokens object.
#future(callout=true)
public static void updateTokens(){
//app info for authenticating
String clientID = 'MY_CLIENT_ID';
String clientSecret = 'MY_CLIENT_SECRET';
//look up value of existing refresh token
Token__c myToken = [SELECT Name, Value__c FROM Token__c WHERE Name='Refresh'];
Token__c myAccessToken = [SELECT Name, Value__c FROM Token__c WHERE Name='Access'];
String refreshToken = myToken.Value__c;
String accessToken = myAccessToken.Value__c;
//variables for storing data
String BoxJSON = '';
String debugTxt = '';
//callout to Box API to get new tokens
HttpRequest reqRefresh = new HttpRequest();
reqRefresh.setMethod('POST');
String endpointRefresh = 'https://www.box.com/api/oauth2/token';
reqRefresh.setEndpoint(endpointRefresh);
String requestBody = ('grant_type=refresh_token&refresh_token=' + refreshToken + '&client_id=' + clientID + '&client_secret=' + clientSecret);
reqRefresh.setBody(requestBody);
System.debug('Body of refresh request: ' + requestBody);
//Create Http, send request
Http httpRefresh = new Http();
Boolean successRefresh = false;
while (successRefresh == false){
try{
HTTPResponse resRefresh = httpRefresh.send(reqRefresh);
BoxJSON = resRefresh.getBody();
System.debug('Body of refresh response: ' + BoxJSON);
successRefresh = true;
}
catch (System.Exception e){
System.debug('Error refreshing: ' + string.valueof(e));
if (Test.isRunningTest()){
successRefresh = true;
}
}
}
Keep in mind that if you are using the Box for Salesforce integration your administrator can set the option for the permissions on the folders to sync with Salesforce permissions. This would reverse any changes you make to collaborations. Check out more about Box's Salesforce integration permissions here: https://support.box.com/hc/en-us/articles/202509066-Box-for-Salesforce-Administration#BfS_admin_perm

Update records using Salesforce REST API - Patch method not working

I'm trying to update a record residing in salesforce table. Im using the Java HttpClient REST API to do the same. Getting an error when we use PATCH to update a record in Salesforce.
PostMethod post = new PostMethod(
instanceUrl + "/services/data/v20.0/sobjects/" +
objectName + "/" + Id + "?_HttpMethod=PATCH"
);
[{"message":"HTTP Method 'PATCH' not allowed. Allowed are HEAD,GET,POST","errorCode":"METHOD_NOT_ALLOWED"}]
Also tried doing the following:
PostMethod post = new PostMethod(
instanceUrl + "/services/data/v20.0/sobjects/" + objectName + "/" + Id)
{
public String getName() { return "PATCH";
}
};
This also returns the same error. We are using apache tomcat with commons-httpclient-3.1.jar library. Please advise on how this can be done.
Please check if you you're using the right implementation of PATCH method, see: Insert or Update (Upsert) a Record Using an External ID.
Also check if your REST URL is correct, probably your objectId is not passed in correctly from Javascript.
The ObjectName is the Name of an Salesforce table i.e. 'Contact'. And Id is the Id of a specific record you want to update in the table.
Similar:
Can I update without an ID?
for Drupal: How to deal with SalesforceException: HTTP Method 'PATCH' not allowed. Allowed are HEAD,GET,POST
As I think you're aware, commons httpclient 3.1 does not have the PATCH method, and the library has been end-of-lifed. In your code above, you're trying to add the HTTP method as a query parameter, which doesn't really make sense.
As seen on SalesForce Developer Board, you can do something like this instead:
HttpClient httpclient = new HttpClient();
PostMethod patch = new PostMethod(url) {
#Override
public String getName() {
return "PATCH";
}
};
ObjectMapper mapper = new ObjectMapper();
StringRequestEntity sre = new StringRequestEntity(mapper.writeValueAsString(data), "application/json", "UTF-8");
patch.setRequestEntity(sre);
httpclient.executeMethod(patch);
This allows you to PATCH without switching out your httpclient library.
I created this method to send the patch request via the Java HttpClient class.
I am using JDK V.13
private static VarHandle Modifiers; // This method and var handler are for patch method
private static void allowMethods(){
// This is the setup for patch method
System.out.println("Ignore following warnings, they showed up cause we are changing some basic variables.");
try {
var lookUp = MethodHandles.privateLookupIn(Field.class, MethodHandles.lookup());
Modifiers = lookUp.findVarHandle(Field.class, "modifiers", int.class);
} catch (IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();
}
try {
Field methodField = HttpURLConnection.class.getDeclaredField("methods");
methodField.setAccessible(true);
int mods = methodField.getModifiers();
if (Modifier.isFinal(mods)) {
Modifiers.set(methodField, mods & ~Modifier.FINAL);
}
String[] oldMethods = (String[])methodField.get(null);
Set<String> methodsSet = new LinkedHashSet<String>(Arrays.asList(oldMethods));
methodsSet.addAll(Collections.singletonList("PATCH"));
String[] newMethods = methodsSet.toArray(new String[0]);
methodField.set(null, newMethods);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}