创建一个名为 All Lusso Scarpe Employees 小组,并向小组提供此描述: This group is for all Lusso Scarpe employees to collaborate and receive company announcements. 所有员工都可以加入该组。
该小组应在页面右侧显示以下信息:recommended groups and individuals to follow and the most popular topics currently under discussion.
公平地说,我们通过创建一个已经准备好了各种各样的好东西的组织,让你在这条路上变得更容易一些。该组织已启用Analytics,它已定义所有必要的权限,并且它包含一个带有一些预加载测试数据的Analytics应用。如果您想了解启用和设置Analytics的管理工作,请查看名为Build and Administer Analytics的跟踪。
还有一件事要做:将新组织连接到Trailhead。
确保您已登录到Trailhead帐户。
在本页底部的“挑战”部分中,从“Trailhead Playground”选项列表中选择“Log into a Developer Edition”。
在登录屏幕上,输入您刚刚设置的Developer Edition的用户名和密码。
在允许访问? 屏幕,单击Allow。
想要连接这个组织进行实际操作的挑战吗? 屏幕,单击 Yes! Save it. 。 您将被重定向回挑战页面并准备好使用新的开发人员版来获得此徽章。
可用于大多数功能,限制应用。 General Shield平台加密注意事项和限制: https://developer.salesforce.com/docs/atlas.en-us.securityImplGuide.meta/securityImplGuide/security_pe_considerations_general.htm
将height属性设置为签名请求中提供的clientHeight值。例如: // Where sr is a parsed signed request object. var h = parseInt(sr.context.environment.dimensions.clientHeight, 10); Sfdc.canvas.byId(‘divElementId’).style.height = h;
导航到指定类型的Feed,作用域为subjectId。对于某些Feed类型,subjectId是必需的但是被忽略。对于这些Feed类型,将当前用户的ID作为subjectId传递。 type是Feed类型。可能的值如下。 •BOOKMARKS:包含上下文用户保存为书签的所有Feed项。将当前用户的ID作为subjectId传递。 •COMPANY:包含除TrackedChange类型的Feed项目之外的所有Feed项目。要查看订阅源项,用户必须具有对其父项的共享访问权限。将当前用户的ID作为subjectId传递。 •文件:包含所有包含上下文用户遵循的人员或组发布的文件的源项目。将当前用户的ID作为subjectId传递。 •GROUPS:包含上下文用户拥有或属于其成员的所有组中的所有Feed项。将当前用户的ID作为subjectId传递。 •新闻:包含上下文用户遵循的所有更新,用户所属的组以及用户所关注的文件和记录。包含父级为上下文用户的记录的所有更新。包含提及上下文用户或提及上下文用户所属的组的每个提要项和注释。将当前用户的ID作为subjectId传递。 •PEOPLE:包含上下文用户遵循的所有人发布的所有Feed项。将当前用户的ID作为subjectId传递。 •RECORD:包含父级为指定记录的所有订阅源项,可以是组,用户,对象,文件或任何其他标准或自定义对象。当记录是一个组时,该提要还包含提及该组的提要项。当记录是用户时,该Feed仅包含该用户的Feed项。您可以获取其他用户的记录Feed。将记录的ID作为subjectId传递。 •TO:包含上下文用户提及的所有Feed项。包含上下文用户注释的订阅源项以及由评论的上下文用户创建的订阅源项。将当前用户的ID作为subjectId传递。 •TOPICS:包含包含指定主题的所有Feed项。将主题的ID作为subjectId传递。仅Salesforce for Mobile Web支持此值。 Salesforce for iOS或Salesforce for Android中不提供主题
// Target a specific canvas app
// where “app1” is the canvasId specified in the canvas component.
// For example:
Sfdc.canvas.controller.publish({name : ‘mynamespace.myevent’,
payload : {},
target : {canvas : ‘app1’}});
// Set the height and width explicitly and target a canvas app
// Where ‘mycanvas0’ is the canvasId on the canvas component
// <apex:canvasApp canvasId=”mycanvas0″/>
var target = {canvas : “mycanvas0”};
Sfdc.canvas.controller.resize( {height : “1000px”, width : “900px”}, target);
// Subscribe to a single event.
Sfdc.canvas.controller.subscribe({name : ‘mynamespace.myevent0’,
onData : function (e) {}});
// Subscribe to multiple events in a single call.
Sfdc.canvas.controller.subscribe([
{name : ‘mynamespace.myevent1’, onData : function(e) {}},
{name : ‘mynamespace.myevent2’, onData : function(e) {}}
]);
This is the default authorization method for canvas apps. The signed request authorization flow varies depending on whether the canvas app’s Permitted Users field is set to “Admin approved users are pre-authorized” or “All users may self-authorize.”
/**
*The utility method can be used to validate/verify the signed request.
*In this case, the signed request is verified that it’s from Salesforce and that
*it has not been tampered with.
*This utility class has two methods. One verifies and decodes the request
*as a Java object, the other as a JSON String.
*/
public class SignedRequest {
public static CanvasRequest verifyAndDecode(String input, String secret)
throws SecurityException {
String[] split = getParts(input);
String encodedSig = split[0];
String encodedEnvelope = split[1];
// Deserialize the JSON body.
String json_envelope = new String(new Base64(true).decode(encodedEnvelope));
ObjectMapper mapper = new ObjectMapper();
ObjectReader reader = mapper.reader(CanvasRequest.class);
CanvasRequest canvasRequest;
String algorithm;
try {
canvasRequest = reader.readValue(json_envelope); algorithm = canvasRequest.getAlgorithm() == null ?
“HMACSHA256” : canvasRequest.getAlgorithm();
} catch (IOException e) {
throw new SecurityException(String.format(“Error [%s] deserializing JSON to Object [%s]”, e.getMessage(), CanvasRequest.class.getName()), e);
}
verify(secret, algorithm, encodedEnvelope, encodedSig);
// If we got this far, then the request was not tampered with.
// Return the request as a Java object.
return canvasRequest;
}
public static String verifyAndDecodeAsJson(String input, String secret) throws SecurityException {
String[] split = getParts(input);
String encodedSig = split[0];
String encodedEnvelope = split[1];
String json_envelope = new String(new Base64(true).decode(encodedEnvelope));
ObjectMapper mapper = new ObjectMapper();
String algorithm; StringWriter writer;
TypeReference<HashMap<String,Object>> typeRef
= new TypeReference<HashMap<String, Object>>() { };
try {
HashMap<String,Object> o = mapper.readValue(json_envelope, typeRef);
writer = new StringWriter();
mapper.writeValue(writer, o);
algorithm = (String)o.get(“algorithm”);
} catch (IOException e) {
throw new SecurityException(String.format(“Error [%s] deserializing JSON to Object [%s]”, e.getMessage(),
typeRef.getClass().getName()), e);
}
verify(secret, algorithm, encodedEnvelope, encodedSig);
// If we got this far, then the request was not tampered with.
// Return the request as a JSON string.
return writer.toString();
}
private static String[] getParts(String input) {
if (input == null || input.indexOf(“.”) <= 0) {
throw new SecurityException(String.format(“Input [%s] doesn’t look like a signed request”, input));
}
String[] split = input.split(“[.]”, 2); return split;
}
private static void verify(String secret, String algorithm, String encodedEnvelope, String encodedSig )
throws SecurityException
{
if (secret == null || secret.trim().length() == 0) {
throw new IllegalArgumentException(“secret is null, did you set your environment variable CANVAS_CONSUMER_SECRET?”);
}
SecretKey hmacKey = null;
try {
byte[] key = secret.getBytes();
hmacKey = new SecretKeySpec(key, algorithm);
Mac mac = Mac.getInstance(algorithm); mac.init(hmacKey);
// Check to see if the body was tampered with.
byte[] digest = mac.doFinal(encodedEnvelope.getBytes());
byte[] decode_sig = new Base64(true).decode(encodedSig);
if (! Arrays.equals(digest, decode_sig)) {
String label = “Warning: Request was tampered with”; throw new SecurityException(label);
}
} catch (NoSuchAlgorithmException e) {
throw new SecurityException(String.format(“Problem with algorithm [%s] Error [%s]”, algorithm, e.getMessage()), e);
} catch (InvalidKeyException e) {
throw new SecurityException(String.format(“Problem with key [%s] Error [%s]”, hmacKey, e.getMessage()), e);
}
// If we got here and didn’t throw a SecurityException then all is good.
}
}
调用verifyAndDecode函数
以下代码显示了获取签名请求,然后使用verifyAndDecode函数验证和解码请求的示例。
// From a JSP or servlet.
<%@ page import=”canvas.SignedRequest” %>
<%@ page import=”java.util.Map” %>
<%
// Pull the signed request out of the request body and verify/decode it. Map<String, String[]> parameters = request.getParameterMap();
String[] signedRequest = parameters.get(“signed_request”); if (signedRequest == null) {%>
This app must be invoked via a signed request!<% return;
}
String yourConsumerSecret=System.getenv(“CANVAS_CONSUMER_SECRET”); String signedRequest = SignedRequest.verifyAndDecode(signedRequest[0],
yourConsumerSecret);
%>
…
// From JavaScript, you can handle the signed request as needed. var signedRequest = ‘<%=signedRequestJson%>’;
// From a JSP or servlet.
<%@ page import=”canvas.SignedRequest” %>
<%@ page import=”java.util.Map” %>
<%
// Pull the signed request out of the request body and verify/decode it. Map<String, String[]> parameters = request.getParameterMap();
String[] signedRequest = parameters.get(“signed_request”); if (signedRequest == null) {%>
This App must be invoked via a signed request!<% return;
}
String yourConsumerSecret=System.getenv(“CANVAS_CONSUMER_SECRET”);
String signedRequestJson = SignedRequest.verifyAndDecodeAsJson(signedRequest[0], yourConsumerSecret);
%>
…
// From JavaScript, you can parse with your favorite JSON library. var signedRequest = JSON.parse(‘<%=signedRequestJson%>’);
// Gets a signed request on demand. Sfdc.canvas.client.refreshSignedRequest(function(data) {
if (data.status === 200) {
var signedRequest = data.payload.response; var part = signedRequest.split(‘.’)[1];
var obj = JSON.parse(Sfdc.canvas.decode(part));
}
}
// Paste the signed request string into a JavaScript object for easy access. var sr = JSON.parse(‘<%=signedRequestJson%>’);
// Reference the Chatter user’s URL from Context.Links object. var chatterUsersUrl = sr.context.links.chatterUsersUrl;
// Make an XHR call back to salesforce through the supplied browser proxy. Sfdc.canvas.client.ajax(chatterUsersUrl,
{client : sr.client, success : function(data){
// Make sure the status code is OK. if (data.status === 200) {
// Alert with how many Chatter users were returned. alert(“Got back ” + data.payload.users.length +
” users”); // Returned 2 users
}
}});
发布到Chatter Feed
以下代码示例显示了将项目发布到上下文用户的Chatter摘要的调用。
var sr = JSON.parse(‘<%=signedRequestJson%>’);
// Reference the Chatter user’s URL from Context.Links object.
var url = sr.context.links.chatterFeedsUrl+”/news/”+sr.context.user.userId+”/feed-items”;
var body = {body : {messageSegments : [{type: “Text”, text: “Some Chatter Post”}]}};
Sfdc.canvas.client.ajax(url,
{client : sr.client, method: ‘POST’,
contentType: “application/json”, data: JSON.stringify(body), success : function(data) {
if (201 === data.status) { alert(“Success”);
}
}
});
// Turn on auto grow with default settings. Sfdc.canvas(function() {
sr = JSON.parse(‘<%=signedRequestJson%>’);
Sfdc.canvas.client.autogrow(sr.client);
});
// Turn on auto grow with polling interval of 100ms (milliseconds). Sfdc.canvas(function() {
sr = JSON.parse(‘<%=signedRequestJson%>’);
Sfdc.canvas.client.autogrow(sr.client, true, 100);
});
// Turn off auto grow. Sfdc.canvas(function() {
sr = JSON.parse(‘<%=signedRequestJson%>’);
Sfdc.canvas.client.autogrow(sr.client, false);
});
// Automatically determine the size. Sfdc.canvas(function() {
sr = JSON.parse(‘<%=signedRequestJson%>’);
Sfdc.canvas.client.resize(sr.client);
});
// Set the height and width explicitly.
Sfdc.canvas(function() {
sr = JSON.parse(‘<%=signedRequestJson%>’);
Sfdc.canvas.client.resize(sr.client, {height : “1000px”, width : “900px”});
});
// Set only the height. Sfdc.canvas(function() {
sr = JSON.parse(‘<%=signedRequestJson%>’);
Sfdc.canvas.client.resize(sr.client, {height : “1000px”});
});
// Subscribe to Streaming API events.
// The PushTopic to subscribe to must be passed in.
// The ‘onComplete’ method may be defined,
// and will fire when the subscription is complete.
Sfdc.canvas(function() {
sr = JSON.parse(‘<%=signedRequestJson%>’);
var handler1 = function(){ console.log(“onData done”);},
handler2 = function(){ console.log(“onComplete done”);};
Sfdc.canvas.client.subscribe(sr.client,
{name : ‘sfdc.streamingapi’, params:{topic:”/topic/InvoiceStatements”}}, onData : handler1, onComplete : handler2}
);
});