Commit 3c40cb35295ddc4d87e5e4a7f5dbac61864369e9

  • avatar
  • alesj
  • Sun Nov 21 00:08:52 GMT 2010
  • Tree SHA1: 28ac6eb
  • Parent SHA1: 0abadba (Updated readme.txt to include submodule init details for when the --recursive was not initially used)
  • raw diff | raw patch
Make updateStatus return post-id.
Allow for diff request factory; e.g. GAE env based on URLFetch.
spring-social-core/src/main/java/org/springframework/social/facebook/FacebookOperations.java
(30 / 14)
  
2525 * Implemented by {@link FacebookTemplate}. Not often used directly, but a
2626 * useful option to enhance testability, as it can easily be mocked or stubbed.
2727 * </p>
28 *
28 *
2929 * <p>
3030 * Many of the methods contained in this interface require an access token from
3131 * Facebook. When a method's description speaks of the "current user", it is
3232 * referring to the user for whom the access token has been issued.
3333 * </p>
34 *
34 *
3535 * @author Craig Walls
36 * @author Ales Justin
3637 */
3738public interface FacebookOperations {
3839 /**
3940 * Retrieves the user's Facebook profile ID.
40 *
41 *
4142 * @return the user's Facebook profile ID.
4243 */
4344 String getProfileId();
4445
4546 /**
4647 * Retrieve the current user's Facebook profile information.
47 *
48 *
4849 * @return the user's profile information.
4950 */
5051 FacebookProfile getUserProfile();
5152
5253 /**
5354 * Retrieve the URL to the user's Facebook profile.
54 *
55 *
5556 * @return the URL to the user's Facebook profile.
5657 */
5758 String getProfileUrl();
5859
5960 /**
6061 * Get a list of the user's friends.
61 *
62 *
6263 * @return a list of <code>String</code>s where each entry is the Facebook
6364 * ID of one of the user's friends.
6465 */
6767
6868 /**
6969 * Posts a message to the current user's wall.
70 *
70 *
71 * @param status
72 * The message to post
73 * @return post id
74 */
75 String updateStatus(String status);
76
77 /**
78 * Posts a message to the current user's wall along with a link.
79 *
7180 * @param message
7281 * The message to post
82 * @param link
83 * A link to be included in the status update, can be null.
84 * @return post id
7385 */
74 void updateStatus(String status);
86 String updateStatus(String message, FacebookLink link);
7587
7688 /**
7789 * Posts a message to the current user's wall along with a link.
78 *
90 *
7991 * @param message
8092 * The message to post
8193 * @param link
82 * A link to be included in the status update
94 * A link to be included in the status update, can be null.
95 * @param fetchPostId
96 * A flag to indicate if we actually fetch post id.
97 * @return post id or null if fetchPostId equals false
8398 */
84 void updateStatus(String message, FacebookLink link);
99 String updateStatus(String message, FacebookLink link, boolean fetchPostId);
85100
86101 /**
87102 * <p>
88103 * Low-level publish-to-Facebook method for publishing any type of object
89104 * supported by Facebook's API.
90105 * </p>
91 *
106 *
92107 * @param object
93108 * The ID of the object to publish to.
94109 * @param connection
115115
116116 /**
117117 * Retrieves the current user's profile picture as an array of bytes.
118 *
118 *
119119 * @return the user's profile picture in bytes.
120120 */
121121 byte[] getProfilePicture();
122122
123123 /**
124124 * Retrieves a user's profile picture as an array of bytes.
125 *
125 *
126126 * @param profileId
127127 * the Facebook ID of the user.
128128 * @return the user's profile picture in bytes.
spring-social-core/src/main/java/org/springframework/social/facebook/FacebookTemplate.java
(66 / 35)
  
2222
2323import org.springframework.http.MediaType;
2424import org.springframework.http.ResponseEntity;
25import org.springframework.http.client.ClientHttpRequestFactory;
2526import org.springframework.http.client.CommonsClientHttpRequestFactory;
2627import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
2728import org.springframework.util.LinkedMultiValueMap;
3232
3333/**
3434 * This is the central class for interacting with Facebook.
35 *
35 *
3636 * <p>
3737 * All operations through Facebook require OAuth 2-based authentication.
3838 * Therefore, FacebookTemplate must be given an access token at construction
3939 * time.
4040 * </p>
41 *
41 *
4242 * <p>
4343 * The easiest way to get an access token is to use the XFBML
4444 * &lt;fb:login-button&gt; tag to require the user to signin to Facebook. Then,
4747 * {@link FacebookWebArgumentResolver} can extract the access token from the
4848 * cookie and make it available as a String argument to the controller method.
4949 * </p>
50 *
50 *
5151 * @author Craig Walls
52 * @author Ales Justin
5253 * @see FacebookWebArgumentResolver
5354 */
5455public class FacebookTemplate implements FacebookOperations {
5858
5959 /**
6060 * Create a new instance of FacebookTemplate.
61 *
61 *
6262 * This constructor creates the FacebookTemplate using a given access token.
63 *
63 *
6464 * @param accessToken
6565 * An access token given by Facebook after a successful OAuth 2
6666 * authentication (or through Facebook's JS library).
6767 */
6868 public FacebookTemplate(String accessToken) {
69 this.accessToken = accessToken;
70 RestTemplate restTemplate = new RestTemplate();
71 // must be CommonsClientHttpRequestFactory or else the location header
72 // in an HTTP 302 won't be followed
73 restTemplate.setRequestFactory(new CommonsClientHttpRequestFactory());
74 MappingJacksonHttpMessageConverter json = new MappingJacksonHttpMessageConverter();
75 json.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "javascript")));
76 restTemplate.getMessageConverters().add(json);
77 this.restOperations = restTemplate;
69 this(accessToken, new CommonsClientHttpRequestFactory());
7870 }
7971
72 /**
73 * Create a new instance of FacebookTemplate.
74 *
75 * This constructor creates the FacebookTemplate using a given access token.
76 *
77 * @param accessToken
78 * An access token given by Facebook after a successful OAuth 2
79 * authentication (or through Facebook's JS library).
80 * @param requestFactory
81 * A request factory; can be useful in restricted environments such as GAE.
82 */
83 public FacebookTemplate(String accessToken, ClientHttpRequestFactory requestFactory) {
84 this.accessToken = accessToken;
85 RestTemplate restTemplate = new RestTemplate();
86 // must be CommonsClientHttpRequestFactory or else the location header
87 // in an HTTP 302 won't be followed
88 restTemplate.setRequestFactory(requestFactory);
89 MappingJacksonHttpMessageConverter json = new MappingJacksonHttpMessageConverter();
90 json.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "javascript")));
91 restTemplate.getMessageConverters().add(json);
92 this.restOperations = restTemplate;
93 }
94
8095 public String getProfileId() {
8196 return Long.toString(getUserProfile().getId());
8297 }
107107
108108 public List<String> getFriendIds() {
109109 @SuppressWarnings("rawtypes")
110 ResponseEntity<Map> response = restOperations.getForEntity(CONNECTION_URL, Map.class, CURRENT_USER, FRIENDS,
111 accessToken);
110 ResponseEntity<Map> response = restOperations.getForEntity(CONNECTION_URL, Map.class, CURRENT_USER, FRIENDS, accessToken);
112111
113112 @SuppressWarnings("unchecked")
114113 Map<String, List<Map<String, String>>> resultsMap = response.getBody();
115114 List<Map<String, String>> friends = resultsMap.get("data");
116
115
117116 List<String> friendIds = new ArrayList<String>();
118117 for (Map<String, String> friendData : friends) {
119118 friendIds.add(friendData.get("id"));
120119 }
121120 return friendIds;
122121 }
123
124 public void updateStatus(String message) {
125 MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
126 map.set("message", message);
127 publish(CURRENT_USER, FEED, map);
122
123 public String updateStatus(String message) {
124 return updateStatus(message, null);
128125 }
129
130 public void updateStatus(String message, FacebookLink link) {
126
127 public String updateStatus(String message, FacebookLink link) {
128 return updateStatus(message, link, true);
129 }
130
131 public String updateStatus(String message, FacebookLink link, boolean fetchPostId) {
131132 MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
132 map.set("link", link.getLink());
133 map.set("name", link.getName());
134 map.set("caption", link.getCaption());
135 map.set("description", link.getDescription());
136 map.set("message", message);
133 map.set("message", message);
134 if (link != null) {
135 map.set("link", link.getLink());
136 map.set("name", link.getName());
137 map.set("caption", link.getCaption());
138 map.set("description", link.getDescription());
139 }
137140 publish(CURRENT_USER, FEED, map);
141
142 if (fetchPostId) {
143 @SuppressWarnings("rawtypes")
144 ResponseEntity<Map> response = restOperations.getForEntity(CONNECTION_URL, Map.class, CURRENT_USER, FEED, accessToken);
145 @SuppressWarnings("unchecked")
146 Map<String, List<Map<String, String>>> resultsMap = response.getBody();
147 List<Map<String, String>> posts = resultsMap.get("data");
148 return posts.get(0).get("id"); // Should exist, as we just posted
149 }
150 else {
151 return null;
152 }
138153 }
139
154
140155 public void publish(String object, String connection, MultiValueMap<String, String> data) {
141156 MultiValueMap<String, String> requestData = new LinkedMultiValueMap<String, String>(data);
142157 restOperations.postForLocation(CONNECTION_URL, requestData, object, connection, accessToken);
143158 }
144
159
145160 public byte[] getProfilePicture() {
146161 return getProfilePicture(CURRENT_USER);
147162 }
148163
149164 public byte[] getProfilePicture(String profileId) {
150 ResponseEntity<byte[]> imageBytes = restOperations.getForEntity(PROFILE_LARGE_PICTURE_URL, byte[].class,
151 profileId, accessToken);
165 ResponseEntity<byte[]> imageBytes = restOperations.getForEntity(PROFILE_LARGE_PICTURE_URL, byte[].class, profileId, accessToken);
152166 return imageBytes.getBody();
153167 }
154
168
155169 static final String PROFILE_LARGE_PICTURE_URL = "https://graph.facebook.com/{profile}/picture?type=large&access_token={accessToken}";
156170 static final String OBJECT_URL = "https://graph.facebook.com/{objectId}";
157171 static final String CONNECTION_URL = OBJECT_URL + "/{connection}?access_token={accessToken}";
158
172
159173 static final String FRIENDS = "friends";
160174 static final String FEED = "feed";
161175 static final String CURRENT_USER = "me";
spring-social-core/src/test/java/org/springframework/social/facebook/FacebookTemplateTest.java
(43 / 12)
  
1515 */
1616package org.springframework.social.facebook;
1717
18import static java.util.Collections.*;
19import static org.junit.Assert.*;
20import static org.junit.internal.matchers.IsCollectionContaining.*;
21import static org.mockito.Matchers.*;
22import static org.mockito.Mockito.*;
23import static org.springframework.http.HttpStatus.*;
24import static org.springframework.social.facebook.FacebookTemplate.*;
25
2618import java.util.ArrayList;
2719import java.util.HashMap;
2820import java.util.List;
2626import org.springframework.util.LinkedMultiValueMap;
2727import org.springframework.util.MultiValueMap;
2828import org.springframework.web.client.RestOperations;
29import static java.util.Collections.singletonMap;
30import static org.junit.Assert.*;
31import static org.junit.internal.matchers.IsCollectionContaining.hasItem;
32import static org.mockito.Matchers.eq;
33import static org.mockito.Mockito.*;
34import static org.springframework.http.HttpStatus.OK;
35import static org.springframework.social.facebook.FacebookTemplate.*;
2936
3037/**
3138 * @author Craig Walls
39 * @author Ales Justin
3240 */
3341public class FacebookTemplateTest {
3442 private static final String ACCESS_TOKEN = "someAccessToken";
7272
7373 @Test
7474 public void getUserProfile() {
75 FacebookProfile fbProfile = setupRestOperationsForGettingProfile();
75 setupRestOperationsForGettingProfile();
76
7677 FacebookProfile actual = facebook.getUserProfile();
7778 assertEquals("Craig", actual.getFirstName());
7879 assertEquals("Walls", actual.getLastName());
120120
121121 @Test
122122 public void updateStatus() {
123 facebook.updateStatus("Hello Facebook!");
123 Map<String, List<Map<String, String>>> resultsMap = new HashMap<String, List<Map<String, String>>>();
124 List<Map<String, String>> postsList = new ArrayList<Map<String, String>>();
125 postsList.add(singletonMap("id", "12345"));
126 postsList.add(singletonMap("id", "67890"));
127 resultsMap.put("data", postsList);
124128
129 ResponseEntity<Map> response = new ResponseEntity<Map>(resultsMap, OK);
130 when(restOperations.getForEntity(eq(CONNECTION_URL), eq(Map.class), eq(CURRENT_USER), eq(FEED),
131 eq(ACCESS_TOKEN))).thenReturn(response);
132
133 assertEquals(facebook.updateStatus("Hello Facebook!"), "12345");
134
125135 MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
126136 map.set("message", "Hello Facebook!");
127137 verify(restOperations).postForLocation(eq(CONNECTION_URL), eq(map), eq(CURRENT_USER), eq(FEED),
140140
141141 @Test
142142 public void updateStatus_withLink() {
143 Map<String, List<Map<String, String>>> resultsMap = new HashMap<String, List<Map<String, String>>>();
144 List<Map<String, String>> postsList = new ArrayList<Map<String, String>>();
145 postsList.add(singletonMap("id", "12345"));
146 postsList.add(singletonMap("id", "67890"));
147 resultsMap.put("data", postsList);
148
149 ResponseEntity<Map> response = new ResponseEntity<Map>(resultsMap, OK);
150 when(restOperations.getForEntity(eq(CONNECTION_URL), eq(Map.class), eq(CURRENT_USER), eq(FEED),
151 eq(ACCESS_TOKEN))).thenReturn(response);
152
143153 String linkUrl = "http://www.springsource.com";
144154 String linkName = "SpringSource";
145155 String linkCaption = "SpringSource Home Page";
146156 String linkDescription = "SpringSource is the leader in Java application and infrastructure management.";
147 facebook.updateStatus("Hello Facebook!", new FacebookLink(linkUrl, linkName, linkCaption, linkDescription));
148157
158 FacebookLink link = new FacebookLink(linkUrl, linkName, linkCaption, linkDescription);
159 assertEquals(facebook.updateStatus("Hello Facebook!", link), "12345");
160
149161 MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
150162 map.set("message", "Hello Facebook!");
151163 map.set("link", linkUrl);
168168 eq(ACCESS_TOKEN));
169169 }
170170
171 @Test
172 public void updateStatus_withNullLink_and_noPostIdFetch() {
173 assertNull(facebook.updateStatus("Hello Facebook!", null, false));
174
175 MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
176 map.set("message", "Hello Facebook!");
177 verify(restOperations).postForLocation(eq(CONNECTION_URL), eq(map), eq(CURRENT_USER), eq(FEED), eq(ACCESS_TOKEN));
178 }
179
171180 private FacebookProfile setupRestOperationsForGettingProfile() {
172181 FacebookProfile fbProfile = new FacebookProfile();
173182 fbProfile.firstName = "Craig";
188188 eq("me"), eq(ACCESS_TOKEN))).thenReturn(fbProfile);
189189 return fbProfile;
190190 }
191
192191
193192}

Comments

Add a new comment:

Login or create an account to post a comment

Add your comment