Can't update OData__ModerationStatus using HTTPSEND - rest

I have tried to update the value of the OData__ModerationStatus column AKA "Approval Status" 3 different ways but only one works. Using VS 2013 the WorkFlow update Item activity from the toolbox and you can see that it's missing X-RequestDigest in the header and does not allow an update to the approval status and results in a security validation error. I believe the error is related to the missing header. Here is the code from the UpdateListItem.
RequestHeaders = (InArgument<DynamicValue>) ((Activity<DynamicValue>) new SetDynamicValueProperties()
{
Properties = {
{
"If-Match",
(InArgument) new InArgument<string>("*")
},
{
"X-HTTP-Method",
(InArgument) new InArgument<string>("MERGE")
},
{
"Accept",
(InArgument) new InArgument<string>("application/json;odata=verbose")
},
{
"Content-Type",
(InArgument) new InArgument<string>("application/json;odata=verbose")
}
}
}),
RequestContent = (InArgument) listItemProperties,
So I used 2 SendHttp activities, one to get the X-RequestDigest using a POST with the url siteurl/_api/contextinfo the second POST using the following headers & Body.
HEADER:
X-RequestDigest:[FormDigestValue from the previous POST]
Accept: application/json; odata=verbose
Content-Type: application/json; odata=verbose
IF-MATCH: *
X-HTTP-Method: MERGE
BODY: [I have tried the following 3]
String.Format("{ '__metadata': { 'type': '" + type + "' },'OData__ModerationStatus':'0' }")
{ '__metadata': { 'type': 'SP.Data.Shared_x0020_DocumentsItem' },
'OData__ModerationStatus':'0' }
Used a BuildDynamicValue activity to set the RequestContent.
All three come error with Microsoft.SharePoint.SPException: Invalid text value. A text field contains invalid data. If I use any other field it works, If i use Fiddler or Advanced Rest Client it updates the value.
Can someone help me understand or explain why it works via REST calls but I can't use VS and the UpdateItem/HTTPSend to set the value.
I have included a image with a successful workflow that updates the Title

We were able to get the scenario working.
After further investigations we could see that the workflow does not have Approve permissions.
We could see this by capturing the REST calls in fiddler for the workflow
{"error":{"code":"-2147024891, System.UnauthorizedAccessException","message":{"lang":"en-US","value":"Access denied. You do not have permission to perform this action or access this resource."},"innererror":{"message":"0x80070005owssvr.dll: (unresolved symbol, module offset=0000000000015BC3) at 0x000007F988885BC3\nMicrosoft.SharePoint.Library.ni.dll
The VS 2013 SP 2013 workflows are really like provider hosted apps and have a default permission which does not include approve items.
Perform the below steps to fix this
• Go to Site Settings  Site App Permissions
Find the App Workflow as copy the first guid as shown below
• Go to http:///_layouts/15/appInv.aspx.
Enter the Guid copied in previous step in the App ID and click on Lookup.
This will populate the Title, App Domain and Redirect URL columns.
Copy the below in Permission Request XML (do NOT change the scope)
<AppPermissionRequests>
<AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="FullControl" /></AppPermissionRequests>
• Tested the workflow again and it started working.

Related

Salesforce Rest API call from typescript using axios

I am trying to fetch records from a scratch org using the tooling API provided by salesforce and user access token. Lets say
accesstoken = "abcd"
url = "https://example.my.salesforce.com/services/data/v49.0/tooling/query?q=SELECT+Id,Name+FROM+Account"
I have used axios node module to make the API call as given below
const options = {
headers: {
"Authorization": "Bearer " + accessToken,
"Content-Type": "application/json"
}
};
axios.get(url, options).then(response => {
console.log(response.status);
if(response.status == 200){
console.log(response.data);
} else {
//do something else
}
});
The call responds with a status 200 i.e the request provided a response. But instead of correct records from Account object, I get the login html page
' Login | Salesforcehtml{visibility:
hidden;}a{color:#0070d2;}body{background-color:#F4F6F9;}#content,.container{background-color:#ffffff;}#header{color:#16325c;}body{display:
table;
width:100%;}#content{margin-bottom:24px;}#wrap{height:100%;} html { visibility: hidden; } if (self == top)
{document.documentElement.style.visibility = 'visible';} else
{document.write = ''; top.location = self.location;
setTimeout(function(){document.body.innerHTML='';},
1);window.self.onload=function(evt){document.body.innerHTML='';};}var
SFDCSessionVars={"server":"https://test.salesforce.com/login/sessionserver212.html","im":true,"ah":"active","save":"Save","saveOne":"Save
1 Change","sum":"#p# Saved Usernames","iaac":false,"hac":"Choose a
Username","suo":"1 Saved Username","title":" |
Salesforce","saveMany":"Save #p#
Changes","lpt":"Login","lllbl":"Lightning
Login","host":"test.salesforce.com","le":false,"heu":"Edit Username
List","ic":false,"lh":false,"ur":"https://business-data-8148-dev-ed.cs79.my.salesforce.com","hidp":"Log
In Using","ih":"inactive","dc":"Username removed. Click Save to Commit
Changes."};LoginHint.hideLoginForm();Edit ListSaveCancel
UsernamePassword Caps Lock is on.Remember
meForgot Your
Password?To go to your company's login
page, enter the custom domain name.Custom Domainhttps://domain.my.salesforce.comContinueBackLog In with a Different
Username© 2020
salesforce.com, inc. All rights reserved.<iframe frameborder="0" src="/s.gif" id="marketing"
name="marketing" scrolling="no" title="Marketing"
tabindex="-1"sandbox="allow-forms allow-pointer-lock allow-popups
allow-same-origin allow-scripts" >LoginLoginHint.getSavedIdentities(false);function
handleLogin(){document.login.un.value=document.login.username.value;document.login.width.value=screen.width;document.login.height.value=screen.height;document.getElementById("Login").disabled=true;document.getElementById("login_form").submit();}function
lazyload(){document.getElementById("pwcapsicon").src="/img/icon/capslock_blue.png";document.getElementById("marketing").src="https://c.salesforce.com/login-messages/promos.html";}loader();
'
Does anyone know what am I missing in here? According to salesforce documentation
https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_query.htm
the accessToken in the header should be enough to make the API call.
Note: I gained the access token by running
sfdx force:user:display -u <username>
Your query is wrong. You selected Tooling API service which is for metadata (info about classes, triggers, objects, fields, deployments, running unit tests...). If you want to query Accounts - that's normal data. Try just /services/data/v49.0/query?q=SELECT+Id,Name+FROM+Account
I don't think you need Content-Type header in there. You don't POST anything. At best you can send Accept (application/json, application/xml)
Are you sure the session id was valid? As in you could go to the org, Setup -> Session management, see it there? Or in the user's login history?
It might be that your SF admin did something nasty like locking sessions down to IP from which they originated or maybe the user doesn't have API access... See if you can create your call in Workbench -> Utilities -> REST Explorer first, then go back to Axios?

Adding group to the Team Folder using API not working

I am having issues when trying to add group to a team folder using the Dropbox API v2.
I am trying to add group to team folder using the 2/sharing/add_folder_member route
I am sending the request with this body:
{
"shared_folder_id": :team_folder_id,
"members": [
{
"member": {
".tag": "dropbox_id",
"dropbox_id": :group_id
},
"access_level": {
".tag": "editor"
}
}
]
}
, and headers:
Authorization [Bearer :team_member_file_access_token],
Dropbox-API-Select-User [:business_account_owner_team_member_id]
The provided user in the headers is member of the group. Because adding user to a group is async operation, I am waiting until the job is complete before sending request to add group to a team folder.
This API call was working fine before, but since the last week always gives access_error - not_a_member error.
Is there a bug with Dropbox, or is there a new way to preform this action?
It turns out that Dropbox has a change in team member file access.
Changing the header Dropbox-API-Select-User to Dropbox-API-Select-Admin fixed the problem.
https://www.dropbox.com/developers/documentation/http/teams#teams-member-file-access

Add a subpanel record to a SugarCRM account through REST API

Question: How do I create a subpanel record through the SugarCRM rest api endpoint for accounts?
Steps taken so far:
I've added a new package called, "transactionHistory" with a module named, "InvoiceHistory" using the SugarCRM studio.
I added a One to Many relationship to the Accounts module using studio.
I'm using NetSuite to push new invoices to the new module's record via the subpanel "create" option. Here's the code I'm using:
function createSugarTransaction(transaction, token) {
var url = 'https://crm.techsoft3d.com/rest/v10/Accounts/' + transaction.customer;
var headers = {
"Content-Type": "application/json",
"OAuth-Token": token
};
var now = (new Date()).toISOString();
var body = {transactionHistory_InvoiceHistory:
{
create: [{
name: transaction.docId,
transaction_date_c: transaction.date,
invoice_status_c: transaction.status,
due_date_c: transaction.duedate,
total_amount_c: transaction.total,
amount_due_c: transaction.remaining,
start_date_c: transaction.startdate,
end_date_c: transaction.enddate
}]
}
};
var response = nlapiRequestURL(url, JSON.stringify(body), headers, 'PUT');
return response;
}
The transaction object has been validated and the json object within the create: [] array has matching sugar fields (key) with the corresponding transaction object values.
When making the API call to sugar I'm successfully authenticated and have access to the custom module and accounts - so no problem there. However, when the call is returned to response it's showing the following error:
{"error":"no_method","error_message":"Could not find a route with 1 elements"}
I'm unsure of what else is needed in order for the record to be created. According to sugar's help documentation and developer community this should work. I'm using the basic information provided by sugarcrm support portal:
http://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_7.6/API/Web_Services/Examples/v10/module_POST/
According to other blog posts within the developer community, it should be as simple as adding the subpanel name, followed by an array of fields under the "create" object... similar to this:
var requestBody = { package_module:create[{name:value}]};
My initial thinking of what's wrong is:
1. my package_module name isn't correct, but I'm unable to find it anywhere within the applicaiton or help documentation.
2. the request body isn't formatted properly, even though it's structure was copied from this article https://developer.sugarcrm.com/2014/02/28/sugarcrm-cookbook2/
Any help would be appreciated.
try the createRelatedRecord api endpoint
type {sugarurl}/rest/v10/help to see a list of endpoints to look through, most of which have documentation and examples
https://crm.techsoft3d.com/rest/v10/help
your API url should have the name of the link (relationship) you want, in addition to the values in the POST payload
https://crm.techsoft3d.com/rest/v10/Accounts/{transaction.customer}/link/accounts_transactionhistory (or whatever your link's name is)
per the documentation for this endpoint, you just specify the field values in the payload
{
"first_name":"Bill",
"last_name":"Edwards"
}

POST to ASP.NET WebAPI using Fiddler2

I have a class that models exactly the entity I have in the database. I have a stored procedure that takes in parameters for a new row and returns all the settings in the table which in turn populates my repository. I am able to see the results of GET, PUT and DELETE in the List of type Setting that is in memory. I am noticing first that even when I close Visual Studio and reopen and run the project, sometimes, the List is still in the state it was before. It is not repopulating from the database so I'm not sure why that is first of all... Secondly, I can't seem to get POST to work from Fiddler unlike the other HTTP verbs. I DO see the values from Fiddler show up in the code below but I get the error: Invalid URI: The format of the URI could not be determined. I get the same error if I pass an ID or not.
Here is what I put into Fiddler:
POST localhost:54852/api/settings
Request Headers
User-Agent: Fiddler
Content-type: application/x-www-form-urlencoded
Host: localhost:54852
Content-Length: 149
Request Body
ID=0&Category=Dried%20Goods&Sub_Category=Other&UnitSize=99&UnitOfMeasureID=999&Facings=true&Quantity=true&EverydayPrice=999.99&PromotionPrice=111.11
PostSetting function within my SettingsController
public HttpResponseMessage PostSetting(Setting item)
{
item = repository.Add(item);
var response = new HttpResponseMessage<Setting>(item) { StatusCode = HttpStatusCode.Created };
string uri = Url.Route("DefaultApi", new { id = item.ID });
response.Headers.Location = new Uri(uri);
return response;
}
Should I create a new procedure that gets the MAXID from the database and use that as the NEW ID in the line above where a new ID is created?
You need to create a JSON representation of the Setting class or item that you are wanting to test with use Fiddler (now a Telerik product) and use the Composer tab.
Next you will want to perform a POST to the following URL:
http://[your base url]/api/settings
and pass the JSON formatted setting class.
You can see an example of this here: ASP.NET Web API - Scott Hanselman
Here is a short video showing how to achieve it easily
get and post to webapi from fiddler

Origin is not allowed by Access-Control-Allow-Origin for HTTP DELETE

I currently playing around with the Facebook JavaScript SDK and the Scores API ( https://developers.facebook.com/docs/score/ ). I wrote a small application to save (post) scores and now I want to delete scores. Posting (saving) them works fine.
My code looks like this:
var deleteHighScoreUrl = 'https://graph.facebook.com/'+facebook.user.id+'/scores?access_token='+facebook.application.id+'|'+facebook.application.secret;
jQuery.ajax(
{
type: 'DELETE',
async: false,
url: deleteHighScoreUrl,
success: function(data, textStatus, jqXHR)
{
console.log('Score deleted.');
}
});
The "facebook" variable is an object that holds my application data. For HTTP POST it works fine but for HTTP DELETE I get the response "NetworkError: 400 Bad Request" in Firebug (with Firefox 10). I saw that Firefox first sends an HTTP OPTIONS (to see if it is allowed to use HTTP DELETE) which leads to this error so I tried the same thing with Google Chrome. Google Chrome sends a real HTTP DELETE which then returns:
"XMLHttpRequest cannot load
https://graph.facebook.com/USER_ID/scores?access_token=APP_ID|APP_SECRET.
Origin MY_DOMAIN is not allowed by Access-Control-Allow-Origin".
I think that this is a classical cross domain issue but how to solve it? I've added my domain to my facebook application (at https://developers.facebook.com/apps) and Facebook has a paragraph which is called "Delete scores for a user". So it must be possible to delete the scores (somehow)?
Because of Cross-Site-Scripting (XSS) a HTTP DELETE is not possible. But you can send a HTTP POST request with the query parameter ?method=delete, which then deletes the score.
Code Sample:
Facebook.prototype.deleteUsersHighScore = function()
{
var deleteHighScoreUrl = 'https://graph.facebook.com/'+this.user.id+'/scores?access_token='+this.application.id+'|'+this.application.secret+'&method=delete';
jQuery.ajax(
{
type: 'POST',
async: false,
url: deleteHighScoreUrl,
success: function(data, textStatus, jqXHR)
{
console.log('Score deleted.');
}
});
}
This is the Cross Domain security issue.
The fact that your error contains the message "Origin MY_DOMAIN" would tell me that somewhere in your code you have copied one of Facebook's examples but not changed the value for MY_DOMAIN to the correct domain you are using.
I would check all of your code for the value "MY_DOMAIN".
Please ignore this advice if you have changed the value to hide your actual domain in your question.