Skip to content

Instantly share code, notes, and snippets.

@zokito
Created September 10, 2018 09:05
Show Gist options
  • Save zokito/e1790277f42a2b35b800c7308a32dba1 to your computer and use it in GitHub Desktop.
Save zokito/e1790277f42a2b35b800c7308a32dba1 to your computer and use it in GitHub Desktop.
JavaScript Remote Site Setting deployment
<apex:page>
<c:RemoteSiteSetting>
<!--
! Need to hit Salesforce APIs from inside Visualforce or Apex?
!
! Put those features here. If the Remote Site Setting is
! present, your components will be rendered normally.
!
! If the Remote Site Setting is absent, instead the page
! blocks using a synchronous XmlHttpRequest that deploys the
! correct endpoint automatically, then refreshes the window.
!-->
</c:RemoteSiteSetting>
</apex:page>
<!--
! The MIT License (MIT)
!
! Copyright (c) 2014 bigass.force.com
!
! Permission is hereby granted, free of charge, to any person obtaining a copy
! of this software and associated documentation files (the "Software"), to deal
! in the Software without restriction, including without limitation the rights
! to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
! copies of the Software, and to permit persons to whom the Software is
! furnished to do so, subject to the following conditions:
!
! The above copyright notice and this permission notice shall be included in
! all copies or substantial portions of the Software.
!
! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
! THE SOFTWARE.
!-->
<apex:component controller="RemoteSiteSettingController">
<apex:outputPanel layout="none" rendered="{!isRssPresent}">
<!-- when Remote Site Setting is present, show contents -->
<apex:componentBody />
</apex:outputPanel>
<apex:outputPanel layout="none" rendered="{!NOT(isRssPresent)}">
<!-- when Remote Site Setting is absent, deploy it! -->
<script type="text/javascript">var __sfdcSessionId = '{!GETSESSIONID()}';</script>
<script src="/soap/ajax/32.0/connection.js" type="text/javascript"></script>
<script>
//calls the Metadata API from JavaScript to create the Remote Site Setting to permit Apex callouts
//http://andyinthecloud.com/2014/07/29/post-install-apex-metadata-api-configuration-solved/
sforce.connection.remoteFunction({
url: 'https://' + window.location.host + '/services/Soap/m/32.0',
onSuccess: function(response, xhr) {
//force reload with no cache
window.location.reload(true);
},
onFailure: function(response, xhr) {
//show bad output
alert(response);
},
method: 'POST',
async: false,
requestHeaders: {
'Content-Type': 'text/xml',
'SOAPAction': '""'
},
requestData: '{!JSENCODE(DeployXml)}',
cache: false,
timeout: 10000
});
</script>
</apex:outputPanel>
</apex:component>
/**
* The MIT License (MIT)
*
* Copyright (c) 2014 bigass.force.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
public class RemoteSiteSettingController {
/**
* Determines if a Remote Site Setting exists for the API hostname of this org.
* eg true (you can interrogate APIs from Apex)
* eg false (we must deploy Remote Site Setting)
*/
static public Boolean isRssPresent {
get {
if (isRssPresent == null) {
//memoize
HttpRequest request = new HttpRequest();
request.setEndpoint(protocolAndHost);
request.setMethod('GET');
try {
new Http().send(request);
isRssPresent = true;
} catch (CalloutException e) {
//probably 'Unauthorized endpoint'
isRssPresent = false;
}
}
return isRssPresent;
}
}
/**
* Determines the true API hostname for a Salesforce org using the Identity API.
* eg 'https://pod.salesforce.com' (most orgs)
* eg 'https://custom.my.salesforce.com' (my domain)
* eg 'https://custom--dev.pod.my.salesforce.com' (sandbox orgs)
*/
static public String protocolAndHost {
get {
if (protocolAndHost == null) {
//memoize
String orgId = UserInfo.getOrganizationId();
String userId = UserInfo.getUserId();
String sessionId = UserInfo.getSessionId();
//use getSalesforceBaseUrl within batches and schedules (not Visualforce), and fix inconsistent protocol
if (sessionId == null) return Url.getSalesforceBaseUrl().toExternalForm().replace('http:', 'https:');
PageReference pr = new PageReference('/id/' + orgId + '/' + userId);
pr.getParameters().put('oauth_token', sessionId);
pr.getParameters().put('format', 'json');
//within test context use url class, else derive from identity api
String data = Test.isRunningTest() ? '{"urls": {"rest": "' + Url.getSalesforceBaseUrl().toExternalForm() + '"}}' : pr.getContent().toString();
Map<String,Object> result = (Map<String,Object>)Json.deserializeUntyped(data);
Map<String,Object> urls = (Map<String,Object>)result.get('urls');
Url rest = new Url((String)urls.get('rest'));
protocolAndHost = rest.getProtocol() + '://' + rest.getHost();
}
return protocolAndHost;
}
}
public String getDeployXml() {
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="RemoteSiteSetting">'
+ '<fullName>Salesforce_API_' + String.valueOf(DateTime.now().getTime()).right(4) + '</fullName>'
+ '<description>Salesforce API</description>'
+ '<disableProtocolSecurity>false</disableProtocolSecurity>'
+ '<isActive>true</isActive>'
+ '<url>' + protocolAndHost + '</url>'
+ '</metadata>'
+ '</createMetadata>'
+ '</env:Body>'
+ '</env:Envelope>'
;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment