Académique Documents
Professionnel Documents
Culture Documents
function loadFriends() {
var req = opensocial.newDataRequest();
var viewerFriendsIdSpec = opensocial.newIdSpec({ "userId" : "VIEWER", "groupId" : "FRIENDS" );
var opt_params = {;
opt_params[opensocial.DataRequest.PeopleRequestFields.MAX] = 100;
req.add(req.newFetchPeopleRequest(viewerFriendsIdSpec, opt_params), 'viewerFriends');
req.send(onLoadFriends);
function onLoadFriends(data) {
var viewerFriends = data.get('viewerFriends').getData();
html = new Array();
html.push('<select id="person">;');
viewerFriends.each(function(person) {
html.push('<option value="' + person.getId() + '">;' + person.getDisplayName() + "</option>;");
);
html.push('</select>;');
document.getElementById('friends').innerHTML = html.join('');
</script>;
<span id="friends"></span>;'''
]]>;
</Content>;
</Module>;
The loadFriends method sends a DataRequest to the OpenSocial container and speciIies the
onLoadFriends method as a callback Iunction. The onLoadFriends method receives a DataResponse
object that contains an opensocial.Collection oI opensocial.Person objects which represent the
user's Iriends. The name oI each oI these Iriends is then added as an option in the drop-down menu. The
drop-down menu, a <select>; element, is then inserted into the 'Iriends' span.
Reqeing gif
Next, let's add a drop-down menu Ior the list oI giIts. We'll request the giIt data, Iormat it into a drop-down
menu, and add it to the HTML in a 'giIts' span. First, add the 'giIts' span at the end oI the application spec:
<?xml version="1.0" encoding="UTF-8"?>;
<Module>;
<ModulePrefs title="Gifts" >;
<Require feature="opensocial-0.8"/>
</ModulePrefs>;
<Content type="html">;
<![CDATA[
<script>;
<-- all the JavaScript -->;
</script>;
'''Give <span id="gifts">;</span>; to <span id="friends">;</span>;.'''
]]>;
</Content>;
</Module>;
Next, create a loadGifts method and invoke it when the page loads.
fncion init() {
01.11.2011 Building an OpenSocial App with Google App Engine - Ope
12/18 wiki.opensocial.myspace.com/index.php?title=Building_an_
fncion init() {
loadFriends();
'''loadGifts();'''
'''function loadGifts() {
var params = {;
params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.JSON;
var url = 'http://openocial-gif-'''''ename'''''.apppo.com/gif';
gadgets.io.makeRequest(url, onLoadGifts, params);
'''
The loadGifts method uses the gadgets.io.MakeRequest method to send a request to the JSON data
API Ior the array oI available giIts. Once we get the response, the callback method, onLoadGifts, will
display the giIts in a drop-down menu.
fncion onLoadGifts(response) {
ar gifts = response.data;
ar html = ne Array();
html.push('<select id="nut">;');
for (ar i = 0; i < gifts.length; i++) {
html.push('<option value="' + gifts[i].key + '">;' + gifts[i].name + '</option>;');
html.push('</select>;');
document.getElementById('gifts').innerHTML = html.join('');
In the loadGiftTransactions method, we'll construct the appropriate URLs to Ietch this data Irom the
data API and use makeRequest to send the requests Ior giIt transaction data. Each call to makeRequest
speciIies a callback method, which is actually a closure so that we can use the friends object built in the
onLoadFriends method when processing the results oI the data request. Here is the implementation Ior the
loadGiftTransactions method and the two callbacks:
fncion loadGiftTransactions(viewer, friends) {
// Ge he gif anacion hee he VIEWER i he ende
ar url = 'http://opensocial-gifts-'''''username'''''/giftTransactions?sender_id=' + viewer.getId();
gadgets.io.makeRequest(url, onLoadGiftsGivenClosure(friends));
// Ge he gif anacion hee he VIEWER i he eceie
ar url = 'http://opensocial-gifts-'''''username'''''/giftTransactions?receiver_id=' + viewer.getId();
01.11.2011 Building an OpenSocial App with Google App Engine - Ope
13/18 wiki.opensocial.myspace.com/index.php?title=Building_an_
ar url = 'http://opensocial-gifts-'''''username'''''/giftTransactions?receiver_id=' + viewer.getId();
gadgets.io.makeRequest(url, onLoadGiftsReceivedClosure(friends));
fncion onLoadGiftsGivenClosure(friends) {
rern fncion(response) {
ar giftTransactions = gadgets.json.parse(response.data);
ar html = ne Array();
html.push('You have given:');
html.push('<ul>');
for (ar i=0; i<giftTransactions.length; i++) {
html.push('<li>' + friends[giftTransactions[i].receiver_id] + ' received ');
html.push(giftTransactions[i].gift_name + '</li>');
html.push('</ul>');
document.getElementById('given').innerHTML = html.join('');
gadgets.window.adjustHeight();
fncion onLoadGiftsReceivedClosure(friends) {
rern fncion(response) {
ar giftTransactions = gadgets.json.parse(response.data);
ar html = ne Array();
html.push('You have received:<ul>');
for (ar i=0; i<giftTransactions.length; i++) {
html.push('<li>' + giftTransactions[i].gift_name + ' from ');
html.push(friends[giftTransactions[i].sender_id] + '</li>');
html.push('</ul>');
document.getElementById('received').innerHTML = html.join('');
gadgets.window.adjustHeight();
Since displaing these gift transactions ma take up more height than the container provides b default, these
callbacks use gadgets.window.adjustHeight to resie the app after inserting the data into the page. In
order to use this new method, ou need to include <Require feature="dynamic-height"/> in the
<ModulePrefs> element of the application spec.
Finall, add the 'given' and 'received' <div> elements to the HTML section of the application spec:
<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="Gifts" >
<Require feature="opensocial-0.8"/>
'''<Require feature="dynamic-height"/>'''
</ModulePrefs>
<Content type="html">
<![CDATA[
<script>
<-- all the JavaScript -->
</script>
Give <span id="gifts"></span> to <span id="friends"></span>.
'''<div id="given"></div>
<div id="received"</div>'''
]]>
</Content>
</Module>
Recording ne gift transactions
The last piece for functionalit to add is the abilit for a user to actuall give a gift to their friend. To do this,
we'll add a "Give!" link to the HTML that will invoke a giveGift JavaScript function when clicked.
<?xml version="1.0" encoding="UTF-8"?>
<Module>
01.11.2011 Building an OpenSocial App with Google App Engine - Ope
14/18 wiki.opensocial.myspace.com/index.php?title=Building_an_
<Module>
<ModulePrefs title="Gifts" >
<Require feature="opensocial-0.8"/>
<Require feature="dynamic-height"/>
</ModulePrefs>
<Content type="html">
<![CDATA[
<script>
<-- all the JavaScript -->
</script>
Give <span id="gifts"></span> to <span id="friends"></span>.
'''<a href="javascript:void(0);" onclick='giveGift();'>Give!</a>'''
<div id="given"></div>
<div id="received"</div>
]]>
</Content>
</Module>
Note: When using links to invoke JavaScript Iunctions, always use href="javascript:void(0);". Using
href="#" causes unexpected results in the container.
The giftGive Iunction just requests the VIEWER Irom the container and sends the receiver and giIt key data
to the callback Iunction Ior that request. In the callback, we make a POST request (using makeRequest) to
the data API that contains the sender and receiver IDs and the key oI the giIt given as post data.
fncion giveGift() {
ar gift_key = document.getElementById('nut').value;
ar receiver_id = document.getElementById('person').value;
ar req = opensocial.newDataRequest();
req.add(req.newFetchPersonRequest(opensocial.IdSpec.PersonId.VIEWER), 'viewer');
req.send(postGiftTransactionClosure(receiver_id, gift_key));
fncion postGiftTransactionClosure(receiver_id, gift_key) {
rern fncion(response) {
ar sender_id = response.get('viewer').getData().getId();
ar params = {;
params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
post_data = gadgets.io.encodeValues({
'sender_id' : sender_id,
'receiver_id' : receiver_id,
'gift_key' : gift_key );
params[gadgets.io.RequestParameters.POST_DATA] = post_data;
ar url = http://openocial-gif-'''''ename'''''/gifTanacion';
gadgets.io.makeRequest(url, loadFriends, params);
Notice that the callback Iunction Ior this makeRequest call is loadFriends. This will basically redraw the
app aIter the giIt transaction is processed.
Sending and verifing signed requests
You don't want just anybody to be able to access your application data through the data API. OpenSocial
containers can add digital signatures to the requests that go out to your servers, or in this case, Google App
Engine.
To send a signed request Irom your OpenSocial app, just change the parameters sent to makeRequest as
Iollows:
fncion postGiftTransactionClosure(receiver_id, gift_key) {
rern fncion(response) {
ar sender_id = response.get('viewer').getData().getId();
ar params = {;
'''params[gadgets.io.RequestParameters.AUTHORIZATION = gadgets.io.AuthorizationType.SIGNED;'''
01.11.2011 Building an OpenSocial App with Google App Engine - Ope
15/18 wiki.opensocial.myspace.com/index.php?title=Building_an_
'''params[gadgets.io.RequestParameters.AUTHORIZATION = gadgets.io.AuthorizationType.SIGNED;'''
params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
post_data = gadgets.io.encodeValues({
'sender_id' : sender_id,
'receiver_id' : receiver_id,
'gift_key' : gift_key );
params[gadgets.io.RequestParameters.POST_DATA] = post_data;
ar url = 'http://opensocial-gifts-'''''username'''''/giftTransactions';
gadgets.io.makeRequest(url, loadFriends, params);
Using signed requests is most important when you're executing actions on the user's behalf since you don't
want a malicious user performing actions for a legitimate user. For example, a malicious user could send
POST requests to the /giftTransactions URL of our data API and include any sender ID, receiver ID, or
gift key. By signing your requests, you can protect your data from unauthorized accessif a request is
forged, you can reply with an error message or nothing at all.
You will need to add code to the api.py class to verify the signature received from the container. We can
implement an _isValidSignature() method and call it before processing GET or POST requests:
'''def _isValidSignature(self):
return False'''
def get(self):
"""Respond with a JSON string representation of the lists of gifts."""
'''if not self._isValidSignature():
self.response.out.write(json.write({))
return'''
if self.request.path.startswith('/gifts'):
self._returnGifts()
elif self.request.path.startswith('/giftTransactions'):
self._returnGiftTransactions()
def post(self):
"""Store a new gift transaction in the datastore based on the POST data."""
'''if not self._isValidSignature():
return'''
giftTransaction = GiftTransaction()
giftTransaction.sender_id = self.request.get('sender_id')
giftTransaction.receiver_id = self.request.get('receiver_id')
giftTransaction.gift = Gift.get(self.request.get('gift_key')).key()
giftTransaction.put()
OpenSocial uses OAuth's method for signing requests and containers may use the HMAC-SHA1 or RSA-
SHA1 algorithms. The following sample code demonstrates the RSA-SHA1 algorithm and assumes the
container is orkut. Orkut's public key is available in an x509 certificate, which has been parsed, converted to
hex value, and hard-coded in the public_key_str variable.
import hashlib
import urllib
import oauth
from Crypto.PublicKey import RSA
from Crypto.Util import number
def _isValidSignature(self):
# Construct a RSA.pubkey object
exponent = 65537
public_key_str = """0x\
00b1e057678343866db89d7dec2518\
99261bf2f5e0d95f5d868f81d600c9\
a101c9e6da20606290228308551ed3\
acf9921421dcd01ef1de35dd3275cd\
4983c7be0be325ce8dfc3af6860f7a\
01.11.2011 Building an OpenSocial App with Google App Engine - Ope
16/18 wiki.opensocial.myspace.com/index.php?title=Building_an_
4983c7be0be325ce8dfc3af6860f7a\
b0bf32742cd9fb2fcd1cd1756bbc40\
0b743f73acefb45d26694caf4f26b9\
765b9f65665245524de957e8c547c3\
58781fdfb68ec056d1"""
public_ke_long = long(public_ke_str, 16)
public_ke = RSA.construct((public_ke_long, eponent))
# Rebuild the message hash locall
oauth_request = oauth.OAuthRequest(http_method=self.request.method,
http_url=self.request.url,
parameters=self.request.params.mied())
message = '&'.join((oauth.escape(oauth_request.get_normalied_http_method()),
oauth.escape(oauth_request.get_normalied_http_url()),
oauth.escape(oauth_request.get_normalied_parameters()),))
local_hash = hashlib.sha1(message).digest()
# Appl the pblic ke to the signature from the remote host
sig = urllib.unquote(self.request.params.mied()["oauth_signature"]).decode('base64')
remote_hash = public_ke.encrpt(sig, '')[0][-20:]
# Verif that the locall-built value matches the value from the remote server.
rern local_hash==remote_hash
The _isValidSignature method uses two third party modules. OAuth's Python client library was written
by Leah Culver and the RSA code is just a small piece oI the pycrypto toolkit. Score one Ior open source!
In case you didn't cut and paste everything just right, this application is hosted in the opensocial-giIts Google
Code project where you can Iind the OpenSocial application spec, the Iull implementation oI the JSON data
API, and all the other Iiles used in this application.
Net Steps
This tutorial has only scratched the surIace oI what you can do with Google App Engine and OpenSocial. Try
adding some oI these Ieatures to your app:
Display pictures Ior each giIt instead oI text (Hint: store the images in your static directory).
Expand the admin interIace to allow more granular access to the data (e.g. delete or update a single
entity rather than resetting everything at once).
Use templates to render the admin interIace.
Include timestamps in giIt transactions and only show recent giIts in the app.
Allow new giIts to be added through the admin interIace.
Let users send a custom message with their giIt.
Create a proIile view Ior the OpenSocial app.
Happy coding!
Resources
Developer Forums
II you have questions while working through this tutorial, you can ask other developers in one oI the Iollowing
Iorums:
Google App Engine Developer Forum
OpenSocial Application Developer Forum
Reference
01.11.2011 Building an OpenSocial App with Google App Engine - Ope
17/18 wiki.opensocial.myspace.com/index.php?title=Building_an_
Reference
Google App Engine
Geing Saed Gide
Daaoe Refeence
Webapp Refeence
OpenSocial
OpenSocial Toial
JaaScip API Refeence
Deelope' Gide
Reieed fom "hp://iki.openocial.mpace.com/inde.php?
ile=Bilding_an_OpenSocial_App_ih_Google_App_Engine"
Vies
Page
Dicion
Vie oce
Hio
Personal tools
Log in / ceae accon
Naigation
Main Page
Conaine
JS API Refeence
Aicle & Toial
Conibing
Recen change
Random page
Help
Search
Go Seach
Toolbo
Wha link hee
Relaed change
Special page
Pinable eion
Pemanen link
Thi page a la modified 23:57, 26 Noembe 2010.
01.11.2011 Building an OpenSocial App with Google App Engine - Ope
18/18 wiki.opensocial.myspace.com/index.php?title=Building_an_
This page was last modified 23:57, 26 November 2010.
This page has been accessed 42,903 times.
Privac polic
About OpenSocial
Disclaimers