How to create a connected app through API? - oauth-2.0

We are building a data integration platform to connect to Salesforce.
Would like to know if there is any documentation to create a connected app programmatically using APIs. I see lot of documentation for creating connected apps via UI but not through API.

You can create Connected Apps through the Metadata API, like any other Salesforce metadata.
The easiest way to do this is to build the Connected App in a Salesforce org and then extract it with a Metadata API client (SFDX, Workbench, CumulusCI, Ant...). Excise the Consumer Key from the metadata, and you'll then be able to deploy that Connected App cleanly into another org.
Note, though, that this is rarely necessary. Connected Apps are global metadata: you typically maintain your Connected App in a single org that you control, and it's then available everywhere. I've really only seen the need to deploy Connected Apps when a different one is needed in each subscriber org.

This code creates connected app.
MetadataService.MetadataPort service = createService();
MetadataService.ConnectedApp connectedApp = new MetadataService.ConnectedApp();
connectedApp.label = 'Test 005';
connectedApp.fullName = 'Test_005';
connectedApp.contactEmail = 'email#email.com';
MetadataService.ConnectedAppOauthConfig oauthConfig = new
MetadataService.ConnectedAppOauthConfig();
oauthConfig.consumerKey = 'yourConsumerKey';
oauthConfig.consumerSecret = 'yourConsumerSecret';
oauthConfig.scopes = new List<String>{'Basic', 'Api', 'Web', 'Full'};
oauthConfig.callbackUrl = 'https://www.google.com/';
connectedApp.oauthConfig = oauthConfig;
List<MetadataService.SaveResult> results = service.createMetadata(new
MetadataService.Metadata[] { connectedApp });

If you don't want to use Metadata API library, you could use the following snippet of code
private static String getSoapBodyXml(String endpoint, String name) {
return ''
+ '<?xml version="1.0" encoding="utf-8"?>'
+ '<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
+ '<env:Header>'
+ '<urn:SessionHeader xmlns:urn="http://soap.sforce.com/2006/04/metadata">'
+ '<urn:sessionId>' + userInfo.getSessionId() + '</urn:sessionId>'
+ '</urn:SessionHeader>'
+ '</env:Header>'
+ '<env:Body>'
+ '<createMetadata xmlns="http://soap.sforce.com/2006/04/metadata">'
+ '<metadata xsi:type="ConnectedApp">'
+ '<fullName>' + name + String.valueOf(DateTime.now().getTime()).right(4) + '</fullName>'
+ '<label>' + name + String.valueOf(DateTime.now().getTime()).right(4) + '</label>'
+ '<contactEmail>julfy#i.ua</contactEmail>'
+ '<oauthConfig>'+
+ '<callbackUrl>' + endpoint + '</callbackUrl>'
+ '<scopes>Full</scopes>'
+ '<scopes>RefreshToken</scopes>'
+ '</oauthConfig>'
+ '</metadata>'
+ '</createMetadata>'
+ '</env:Body>'
+ '</env:Envelope>'
;
}
public static HttpResponse add(String endpoint, String name) {
HttpRequest req = new HttpRequest();
req.setEndpoint(URL.getOrgDomainUrl().toExternalForm() + '/services/Soap/m/50.0');
req.setMethod('POST');
req.setHeader('Content-Type', 'text/xml');
req.setHeader('SOAPAction', '""');
req.setBody(getSoapBodyXml(endpoint, name));
HttpResponse r = new Http().send(req);
System.debug('add getBody: ' + r.getBody());
System.debug('add getStatus: ' + r.getStatus());
System.debug('add getStatusCode: ' + r.getStatusCode());
val(r);
return r;
}
private static void val(HttpResponse r) {
System.debug('success? ' + r.getBody().contains('<success>true</success>'));
if (!r.getBody().contains('<success>true</success>')) {
throw new UnexpectedException(r.getBody().substringBetween('<statusCode>', '</statusCode>') + ': ' + r.getBody().substringBetween('<message>', '</message>'));
}
}
public static HttpResponse deploy(Integer i) {
return add(
'https://google.com',
'DeployedApp' + i
);
}

Related

Google oauth2 works fine in localhost but not works in domain

I am trying to integrated Google Calendar Integration to my web site. Everything run on local host is perfect. But when I publish it in to domain it give me some error.
This bt.mypage.kr page can’t be foundNo webpage was found for the web
address:
http://bt.mypage.kr/o/oauth2/v2/auth?scope=https://www.googleapis.com/auth/calendar+https://www.googleapis.com/auth/calendar.events&access_type=online&include_granted_scopes=true&response_type=code&state=state_parameter_passthrough_value&redirect_uri=http://bt.mypage.kr/Schedule/UI/oauth2callback&client_id=myclientid
My code some thing like this:
public ActionResult AuthRedirect()
{
var url = "http://" + Request.Host;
sting redirect_uri = url + "/Schedule/UI/oauth2callback"
GoogleParram gpr = new GoogleParram(url);
string rerectUrl = "https://accounts.google.com/o/oauth2/v2/auth?" +
"scope=https://www.googleapis.com/auth/calendar+https://www.googleapis.com/auth/calendar.events&" +
"access_type=online&" +
"include_granted_scopes=true&" +
"response_type=code&" +
"state=state_parameter_passthrough_value&" +
"redirect_uri=" + url + "/Schedule/UI/oauth2callback&" +
"client_id=" + gpr.client_id;
return Redirect(rerectUrl);
}
public void oauth2callback(string code, string error, string state)
{
if (string.IsNullOrWhiteSpace(error))
{
this.GetTokens(code);
}
}
public IActionResult GetTokens(string code)
{
var url = "http://" + Request.Host;
GoogleParram gpr = new GoogleParram(url);
var request = new RestRequest();
request.AddQueryParameter("client_id", gpr.client_id);
request.AddQueryParameter("client_secret", gpr.client_secret);
request.AddQueryParameter("code", code);
request.AddQueryParameter("grant_type", "authorization_code");
request.AddQueryParameter("redirect_uri", url + "/Schedule/UI/oauth2callback&");
RestClient restClient = new RestClient(gpr.token_uri);
var response = restClient.Post(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
gpr.WriteToken(response.Content);
return RedirectToAction("Calendar");
}
return RedirectToAction("Calendar");
}
My Credentials
I hope anybody knows how to solve. Bundle of Thanks in advance.

Screenshot is not attached to the extend report when ran in Jenkins only

When using remote-webdriver instance of BrowserStack, only when ran in Jenkins, the failed screenshot is not attached to the report. please help. folder structure is ExtentReport\Screenshots
I tried Extent Report: Not able to see the screenshots on other machine
this but it's not resolve the issue.
public void onTestFailure(ITestResult result) {
testMap.get().fail(result.getThrowable());
//add screenshot for failed test.
WebDriver driver= WebDriverFactory.getDriver();
//experimental to get screenshot
driver = new Augmenter().augment(driver);
String dateName = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date());
TakesScreenshot ts = (TakesScreenshot) driver;
File source = ts.getScreenshotAs(OutputType.FILE);
String destination = System.getProperty("user.dir") + "/ExtentReport/" + "/Screenshots/" + result.getMethod().getMethodName() + dateName + ".png";
File finalDestination = new File(destination);
try {
FileUtils.copyFile(source, finalDestination);
} catch (IOException e) {
e.printStackTrace();
}
testMap.get().addScreenCaptureFromPath(destination,result.getMethod().getMethodName());
}
Different operating systems use different characters as file and path separators. When our application has to run on multiple platforms, we need to handle these correctly.
To handle this issue Java provide File.separator.
So, instead of
String destination = System.getProperty("user.dir") + "/ExtentReport/" + "/Screenshots/" + result.getMethod().getMethodName() + dateName + ".png";
Try this:
String destination = System.getProperty("user.dir") + File.separator + "ExtentReport" + File.separator +"Screenshots" + File.separator + result.getMethod().getMethodName() + dateName + ".png";
To use it you will have to add this import
import java.io.File;
Based on the answer of ravi creed,
HTML : Unable to view the base64 image in html report
String base64Screenshot ="data:image/png;base64," + ((TakesScreenshot) Objects.requireNonNull(driver)).getScreenshotAs(OutputType.BASE64);
testMap.get().addScreenCaptureFromBase64String(base64Screenshot).getModel().getMedia().get(0);
I managed to solve this using above code.Once click on base64 img, it opens the actual screenshot.

Directions API is not working on a physical device

I write an app on Xamarin.Android. Directions API works perfectly when debugging on emulator. But it doesn't work when testing on a physical device. I suppose the problem can be in http request. Is somebody familiar with such a problem?
public async Task<string> GetDirectionJsonAsync(LatLng location, LatLng destLocation, string mapkey)
{
// Origin of route
string str_origin = "origin=" + location.Latitude.ToString() + "," + location.Longitude.ToString();
// Destination of route
string str_destination = "destination=" + destLocation.Latitude.ToString() + "," + destLocation.Longitude.ToString();
// Mode
string mode = "mode=driving";
string parameters = str_origin + "&" + str_destination + "&" + mode + "&key=" + mapkey;
// Output
string output = "json";
string url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters;
var handler = new HttpClientHandler();
HttpClient client = new HttpClient(handler);
string jsonString = await client.GetStringAsync(url);
return jsonString;
}

File Read-Write Error in iOS

I have used following code for file reading and writing.
private void StorePuzzleData ()
{
FileInfo fileInfo = new FileInfo (Application.persistentDataPath + "\\" + difficultyLevel + puzzleId + ".txt");
if (fileInfo.Exists)
fileInfo.Delete ();
string fileData = string.Empty;
foreach (CellInformation cellInfo in cellInfoList)
fileData += cellInfo.RowIndex + "#" + cellInfo.ColIndex + "#" + cellInfo.number + "#" + cellInfo.CellColor + "#" + cellInfo.CellDisplayColor + "#" + (cellInfo.IsGroupComplete ? 1 : 0) + ",";
StreamWriter streamWriter = fileInfo.CreateText ();
streamWriter.WriteLine (fileData);
streamWriter.Close ();
DataStorage.StorePuzzleTimePassed (difficultyLevel, puzzleId, GameController.gamePlayTime);
}
private void ReadPuzzleData ()
{
// format: rownumber, colnumber, number, cellcolor, celldisplaycolor, isgroupcomplete
StreamReader streamReader = File.OpenText (Application.persistentDataPath + "\\" + difficultyLevel + puzzleId + ".txt");
string fileData = streamReader.ReadLine ();
}
But I am getting following error in actual iOS device running. This code working correct in iMac as well in android device.
Please give me some suggestion what changes I need to do to make this correct.
It seems you're using Windows-style paths in a Unix-like (Apple Mac OS) environment. Notice that on windows you have paths with a backslash like
C:\Users\Maxi\Desktop
On Unix-like system however something like
/var/mobile/Containers
You notice that in your faulty path you have mixed forward and backward slashes, which makes the path invalid.
/var/mobile/Containers/Data/Application/2.....\debutan1.txt
The correct way to always generate the correct path is to use the Path.Combine(string, string) function. This will combine two paths using the correct directory path seperator, which can also be seperatly accessed through Path.DirectorySeparatorChar.
So, in order to make your code correct, you would do
using System.IO; /* must be imported */
private void StorePuzzleData ()
{
FileInfo fileInfo = new FileInfo (Path.Combine(Application.persistentDataPath, difficultyLevel + puzzleId + ".txt"));
if (fileInfo.Exists)
fileInfo.Delete ();
string fileData = string.Empty;
foreach (CellInformation cellInfo in cellInfoList)
fileData += cellInfo.RowIndex + "#" + cellInfo.ColIndex + "#" + cellInfo.number + "#" + cellInfo.CellColor + "#" + cellInfo.CellDisplayColor + "#" + (cellInfo.IsGroupComplete ? 1 : 0) + ",";
StreamWriter streamWriter = fileInfo.CreateText ();
streamWriter.WriteLine (fileData);
streamWriter.Close ();
DataStorage.StorePuzzleTimePassed (difficultyLevel, puzzleId, GameController.gamePlayTime);
}
private void ReadPuzzleData ()
{
// format: rownumber, colnumber, number, cellcolor, celldisplaycolor, isgroupcomplete
StreamReader streamReader = File.OpenText (Path.Combine(Application.persistentDataPath, difficultyLevel + puzzleId + ".txt"));
string fileData = streamReader.ReadLine ();
}
If this still gives an "Access denied" error it must be because of filepermissions. Post the output of ls -la <thatpath> then.

Blackberry: Command line build and application auto-start

I have an application which is built from command line (ANT) using J2ME Polish. As such, this application is defined through a build.xml, not from Blackberry JDE project files.
What I need to do is have this application auto-start. This is easy enough to do once the application has been run for the first time (example). However, this does require the application to be manually run by the user (which I want to avoid).
The JDE provides options which you can check to enable auto-start, and from ANT:
<cldc runonstartup=="true"...
Will do the trick. The question is, how do I integrate this into a Polish buiild (i.e. into a Polish build.xml which is also building for other platforms)?
Anyone know what the auto-start option in the JDE actually does / what it changes?
So, the way to do this is, unfortunately, to change the J2ME-Polish source! As outlined in this bug report the J2ME Polish build framework (at version 2.1.4) doesn't pass on the RIM-MIDlet-Flags-x JAD attribute to RAPC.
The changes are relatively simple - merely passing on the RIM-MIDlet-Flags-1 value if defined in the JAD, otherwise setting it to zero (as the original 2.1.4 source does).
The diff (from 2.1.4) source:
Index: /enough-polish-build/source/extensions/de/enough/polish/blackberry/JarToCodFinalizer.java
===================================================================
--- /enough-polish-build/source/extensions/de/enough/polish/blackberry/JarToCodFinalizer.java (revision 315)
+++ /enough-polish-build/source/extensions/de/enough/polish/blackberry/JarToCodFinalizer.java (revision 316)
## -36,6 +36,7 ##
import java.util.Calendar;
import java.util.Locale;
import java.util.Map;
+import java.util.List;
import java.util.Properties;
import org.apache.tools.ant.BuildException;
## -185,6 +186,13 ##
}
}
File iconFile = null;
+ Map jadProperties;
+ try {
+ jadProperties = FileUtil.readPropertiesFile( jadFile, ':' );
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new BuildException("Unable to read JAD file " + e.toString() );
+ }
if (mainClassName != null) {
try {
/*
## -230,12 +238,26 ##
"MicroEdition-Configuration: CLDC-1.1",
//"MIDlet-1: Demo," + iconUrl + ",",
"MIDlet-1: " + env.getVariable("MIDlet-Name") + "," + iconUrl + ",",
- //"MIDlet-Icon: " + iconUrl,
- "RIM-MIDlet-Flags-1: 0"
+ //"MIDlet-Icon: " + iconUrl
};
+ /* Ensure that if RIM-MIDlet-Flags is defined in the JAD, it is
+ * passed on to RAPC to create the COD file.
+ * See https://developer.berlios.de/bugs/?func=detailbug&group_id=1246&bug_id=16901
+ * for details.
+ */
+ ArrayList newEntriesList = new ArrayList(Arrays.asList(newEntries));
+ final String flagsKey = "RIM-MIDlet-Flags-1";
+ String flagString = (String)jadProperties.get(flagsKey);
+ if (flagString == null) {
+ flagString = "0";
+ }
+ flagString = flagString.trim();
+ System.out.println("JarToCodFinalizer setting " + flagsKey + ": " + flagString);
+ newEntriesList.add(flagsKey+ ": " + flagString);
+
File rapcFile = new File( jadFile.getParent(), codName + ".rapc");
- FileUtil.writeTextFile( rapcFile, newEntries );
+ FileUtil.writeTextFile( rapcFile, newEntriesList );
} catch ( IOException e ) {
// this shouldn't happen
e.printStackTrace();
## -367,7 +389,6 ##
// now rewrite JAD file so that it is ready for OTA download:
// (first backup JAD file:)
//FileUtil.copy(jadFile, new File(jadFile.getParent(), jadFile.getName() + ".bak") );
- Map jadProperties = FileUtil.readPropertiesFile( jadFile, ':' );
Object[] keys = jadProperties.keySet().toArray();
for (int i = 0; i < keys.length; i++) {
String key = (String) keys[i];
Another polish user :)
Take a look at BB forums the 2nd post. Then using what we know about polish and jad attributes
Add this to your jad section of your build.xml
<jad>
<attribute name="RIM-MIDlet-Flags"
value="1"
if="polish.vendor == BlackBerry" />
</jad>
I haven't tested this but the logic seems to be valid :) Let me know if it works or not.

Resources